我正在把头发拉出来;它应该是如此简单,但我无法弄清楚这个问题。
我正在尝试在我的模块中保存一些自定义设置。我使用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;
}
}
模型/ 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 /零件/ 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 ,我可以通过主菜单中“设置”下方的“自定义”菜单项访问视图。视图加载正常,当我输入一些详细信息并单击“保存”时,表单将被发送到find并将点击 CustomSettingsPartDriver.cs DriverResult Editor(CustomSettingsPart part, IUpdateModel updater..
方法。
我相信这就是问题所在,因为它没有触及return ContentShape("Parts_CustomSettings_Edit, () => {
lambda表达式中的任何断点。
有人能说清楚如何解决这个问题吗?我确定这是一个简单的问题,但我一直试图将这个问题弄清楚一段时间没有成功。谢谢!
答案 0 :(得分: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
}
*捂脸*