2

我在这个上拔头发;它应该很简单,但我无法弄清楚问题所在。

我试图在我的模块中简单地保存一些自定义设置。我以 Orchard.Email 模块为例说明如何插入“设置”菜单;我的代码如下:

迁移.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;
    }
}

模型/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)));
    }
}

处理程序/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")));
    }
}

驱动程序/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/Parts/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, () => {lambda 表达式中遇到任何断点。

谁能阐明我如何解决这个问题?我确信这是一个简单的问题,但我一直试图解决这个问题一段时间,但没有成功。谢谢!

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 回答