2

私はこれで髪を引っ張っています。とても単純なはずですが、問題がわかりません。

モジュールにいくつかのカスタム設定を保存しようとしています。「設定」メニューにプラグインする方法の例として、Orchard.Email モジュールを使用しました。私のコードは次のとおりです。

Migrations.cs

public class CustomSettingsMigrations : DataMigrationImpl {
    public int Create() {
        SchemaBuilder.CreateTable("CustomSettingsPartRecord", table => table
            .ContentPartRecord()
            .Column<string>("GatewayUrl")
            .Column<string>("MerchantId")
            .Column<string>("MerchantPassword")
            .Column<bool>("SandboxMode")
            .Column<string>("SandboxGatewayUrl")
            .Column<string>("SandboxMerchantId")
            .Column<string>("SandboxMerchantPassword")
            );

            return 1;
    }
}

Models/CustomSettingsPartRecord.cs

public class CustomSettingsPartRecord : ContentPartRecord {
    public virtual string GatewayUrl { get; set; }
    public virtual string MerchantId { get; set; }
    public virtual string MerchantPassword { get; set; }
    public virtual bool SandboxMode { get; set; }
    public virtual string SandboxGatewayUrl { get; set; }
    public virtual string SandboxMerchantId { get; set; }
    public virtual string SandboxMerchantPassword { get; set; }

    public CustomSettingsPartRecord() {
        SandboxMode = true;
    }
}

モデル/CustomSettingsPart.cs

public class CustomSettingsPart : ContentPart<CustomSettingsPartRecord> {
    private readonly ComputedField<string> _password = new ComputedField<string>();

    public ComputedField<string> PasswordField {
        get { return _password; }
    }

    public string GatewayUrl {
        get { return Record.GatewayUrl; }
        set { Record.GatewayUrl = value; }
    }

    public string MerchantId {
        get { return Record.MerchantId; }
        set { Record.MerchantId = value; }
    }

    public string MerchantPassword {
        get { return Record.MerchantPassword; }
        set { Record.MerchantPassword = value; }
    }

    public bool SandboxMode {
        get { return Record.SandboxMode; }
        set { Record.SandboxMode = value; }
    }

    public string SandboxGatewayUrl {
        get { return Record.SandboxGatewayUrl; }
        set { Record.SandboxGatewayUrl = value; }
    }

    public string SandboxMerchantId {
        get { return Record.SandboxMerchantId; }
        set { Record.SandboxMerchantId = value; }
    }

    public string SandboxMerchantPassword {
        get { return Record.SandboxMerchantPassword; }
        set { Record.SandboxMerchantPassword = value; }
    }

    public bool IsValid() {
        return ((!String.IsNullOrWhiteSpace(Record.GatewayUrl)
                 && !String.IsNullOrWhiteSpace(Record.MerchantId)) ||
                (Record.SandboxMode && !String.IsNullOrWhiteSpace(Record.SandboxGatewayUrl) &&
                 !String.IsNullOrWhiteSpace(Record.SandboxMerchantId)));
    }
}

Handlers/CustomSettingsPartHandler.cs

[UsedImplicitly]
public class CustomSettingsPartHandler : ContentHandler {
    private readonly IEncryptionService _encryptionService;

    public CustomSettingsPartHandler(IRepository<CustomSettingsPartRecord> repository, IEncryptionService encryptionService) {
        T = NullLocalizer.Instance;
        Logger = NullLogger.Instance;

        _encryptionService = encryptionService;
        Filters.Add(new ActivatingFilter<CustomSettingsPart>("Site"));
        Filters.Add(StorageFilter.For(repository));

        OnLoaded<CustomSettingsPart>(LazyLoadHandlers);
    }

    public Localizer T { get; set; }
    public new ILogger Logger { get; set; }

    void LazyLoadHandlers(LoadContentContext context, CustomSettingsPart part) {
        part.PasswordField.Getter(() => {
            try {
                return String.IsNullOrWhiteSpace(part.Record.MerchantPassword) ? String.Empty : Encoding.UTF8.GetString(_encryptionService.Decode(Convert.FromBase64String(part.Record.MerchantPassword)));
            }
            catch (Exception) {
                Logger.Error("The merchant password could not be decrypted. It might be corrupt, try to reset it.");
                return null;
            }
        });

        part.PasswordField.Setter(value => part.Record.MerchantPassword = String.IsNullOrWhiteSpace(value) ? String.Empty : Convert.ToBase64String(_encryptionService.Encode(Encoding.UTF8.GetBytes(value))));
    }

    protected override void GetItemMetadata(GetContentItemMetadataContext context) {
        if (context.ContentItem.ContentType != "Site")
            return;
        base.GetItemMetadata(context);
        context.Metadata.EditorGroupInfo.Add(new GroupInfo(T("Custom")));
    }
}

Drivers/CustomSettingsPartDriver.cs

public class CustomSettingsPartDriver : ContentPartDriver<CustomSettingsPart> {
    private const string TemplateName = "Parts/CustomSettings";

    public CustomSettingsPartDriver() {
        T = NullLocalizer.Instance;
    }

    public Localizer T { get; set; }

    protected override string Prefix { get { return "CustomSettings"; } }

    protected override DriverResult Editor(CustomSettingsPart part, dynamic shapeHelper) {
        return ContentShape("Parts_CustomSettings_Edit",
            () => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: part, Prefix: Prefix))
            .OnGroup("custom");
    }

    protected override DriverResult Editor(CustomSettingsPart part, IUpdateModel updater, dynamic shapeHelper) {
        return ContentShape("Parts_CustomSettings_Edit", () => {
            var previousPassword = part.MerchantPassword;
            updater.TryUpdateModel(part, Prefix, null, null);

            // restore password if the input is empty, meaning it has not been changed
            if (String.IsNullOrEmpty(part.MerchantPassword)) {
                part.MerchantPassword = previousPassword;
            }
            return shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: part, Prefix: Prefix)
            .OnGroup("custom");
        });
    }
}

ビュー/EditorTemplates/パーツ/CustomSettings.cshtml

@model CustomModule.Models.CustomSettingsPart
@{
    Script.Require("jQuery");            
}
<fieldset>
    <legend>@T("Custom Settings")</legend>
    <div>
        <label for="@Html.FieldIdFor(m => m.GatewayUrl)">@T("Gateway Url")</label>
        @Html.EditorFor(m => m.GatewayUrl)
        @Html.ValidationMessage("GatewayUrl", "*")
    </div>
    <div>
        <label for="@Html.FieldIdFor(m => m.MerchantId)">@T("Merchant ID")</label>
        @Html.EditorFor(m => m.MerchantId)
        @Html.ValidationMessage("MerchantId", "*") 
    </div>
    <div>
        <label for="@Html.FieldIdFor(m => m.MerchantPassword)">@T("Merchant Password")</label>
        @Html.PasswordFor(m => m.MerchantPassword)
        @Html.ValidationMessage("MerchantPassword", "*")
    </div>
    <div>
        @Html.EditorFor(m => m.SandboxMode)
        <label for="@Html.FieldIdFor(m => m.SandboxMode)" class="forcheckbox">@T("Enable Sandbox Mode (for testing)")</label>
        @Html.ValidationMessage("SandboxMode", "*")
    </div>
    <div id="sandboxSettings">
        <div>
            <label for="@Html.FieldIdFor(m => m.SandboxGatewayUrl)">@T("Sandbox Gateway Url")</label>
            @Html.EditorFor(m => m.SandboxGatewayUrl)
            @Html.ValidationMessage("SandboxGatewayUrl", "*")
        </div>
        <div>
            <label for="@Html.FieldIdFor(m => m.SandboxMerchantId)">@T("Sandbox Merchant ID")</label>
            @Html.EditorFor(m => m.SandboxMerchantId)
            @Html.ValidationMessage("SandboxMerchantId", "*") 
        </div>
        <div>
            <label for="@Html.FieldIdFor(m => m.SandboxMerchantPassword)">@T("Sandbox Merchant Password")</label>
            @Html.EditorFor(m => m.SandboxMerchantPassword)
            @Html.ValidationMessage("SandboxMerchantPassword", "*")
        </div>
    </div>
</fieldset>
@using (Script.Foot()) {
    <script>
        $('#@Html.FieldIdFor(m => m.SandboxMode)').on('click', function() {
            $('#sandboxSettings').toggle($(this).prop('checked'));
        });
    </script>
}

Placement.infoがあり、メイン メニューの [設定] の下にある [カスタム] メニュー項目からビューにアクセスできます。ビューが正常に読み込まれ、詳細を入力して [保存] をクリックすると、フォームが送られ、検索結果がCustomSettingsPartDriver.cs DriverResult Editor(CustomSettingsPart part, IUpdateModel updater..メソッドにヒットします。

ラムダreturn ContentShape("Parts_CustomSettings_Edit, () => {式内のブレークポイントにヒットしないため、これが問題の可能性がある場所だと思います。

どうすればこれを解決できるか、誰かが光を当てることができますか? 単純な問題だと思いますが、しばらくの間、これを理解しようとして失敗しました。ありがとう!

4

1 に答える 1

1

さて、私はこれを理解することができました。質問をしてから自分で答えるのはばかげていると思いますが、将来一人の時間を節約できるのであれば、それだけの価値があります。

問題は、予想どおり、ドライバーにありました。.OnGroup()拡張機能を間違った形状に追加しました。

以下は、修正されたドライバー コードです。

protected override DriverResult Editor(CustomSettingsPart part, IUpdateModel updater, dynamic shapeHelper) {
    return ContentShape("Parts_CustomSettings_Edit", () => {
        var previousPassword = part.MerchantPassword;
        updater.TryUpdateModel(part, Prefix, null, null);

        // restore password if the input is empty, meaning it has not been changed
        if (String.IsNullOrEmpty(part.MerchantPassword)) {
            part.MerchantPassword = previousPassword;
        }
        return shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: part, Prefix: Prefix);
        // Offending extension -> .OnGroup("custom");

    }).OnGroup("custom"); // In the correct location
}

*フェイスパーム*

于 2013-05-22T04:15:54.013 に答える