我有一个这样的模型:
return new MyViewModel()
{
Name = "My View Model",
Modules = new IRequireConfig[]
{
new FundraisingModule()
{
Name = "Fundraising Module",
GeneralMessage = "Thanks for fundraising"
},
new DonationModule()
{
Name = "Donation Module",
MinDonationAmount = 50
}
}
};
IRequireConfig接口公开了一个DataEditor字符串属性,该视图用于传递给@ Html.EditorFor,如下所示:
@foreach (var module in Model.Modules)
{
<div>
@Html.EditorFor(i => module, @module.DataEditor, @module.DataEditor) //the second @module.DataEditor is used to prefix the editor fields
</div>
}
当我将其发布回我的控制器时,TryUpdateModel将Modules属性保留为null。这是非常期待的,因为我不希望它知道要反序列化的具体类。
由于我在帖子进来时仍然可以使用原始模型,因此我可以循环使用模块并使用.GetType()获取其类型。似乎在这一点上我有足够的信息让TryUpdateModel尝试反序列化模型,但问题是它使用泛型类型推断来驱动反序列化器,因此它实际上不会更新任何属性,除了在接口
如何使用新值更新我的Modules数组?
如果有任何特殊要点不清楚请告诉我,我会尽力澄清
答案 0 :(得分:1)
您可以使用自定义模型绑定器。假设您有以下型号:
public interface IRequireConfig
{
string Name { get; set; }
}
public class FundraisingModule : IRequireConfig
{
public string Name { get; set; }
public string GeneralMessage { get; set; }
}
public class DonationModule : IRequireConfig
{
public string Name { get; set; }
public decimal MinDonationAmount { get; set; }
}
public class MyViewModel
{
public string Name { get; set; }
public IRequireConfig[] Modules { get; set; }
}
控制器:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
Name = "My View Model",
Modules = new IRequireConfig[]
{
new FundraisingModule()
{
Name = "Fundraising Module",
GeneralMessage = "Thanks for fundraising"
},
new DonationModule()
{
Name = "Donation Module",
MinDonationAmount = 50
}
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
查看:
@model MyViewModel
@using (Html.BeginForm())
{
@Html.EditorFor(x => x.Name)
for (int i = 0; i < Model.Modules.Length; i++)
{
@Html.Hidden("Modules[" + i + "].Type", Model.Modules[i].GetType())
@Html.EditorFor(x => x.Modules[i])
}
<input type="submit" value="OK" />
}
最后是自定义模型绑定器:
public class RequireConfigModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var typeParam = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Type");
if (typeParam == null)
{
throw new Exception("Concrete type not specified");
}
var concreteType = Type.GetType(typeParam.AttemptedValue, true);
var concreteInstance = Activator.CreateInstance(concreteType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => concreteInstance, concreteType);
return concreteInstance;
}
}
您将在Application_Start
注册:
ModelBinders.Binders.Add(typeof(IRequireConfig), new RequireConfigModelBinder());
现在提交表单时,将发送Type并且模型绑定器将能够实例化正确的实现。