如何在 MVC 视图中绑定派生类型





5.00/5 (3投票s)
如何在 MVC 视图中绑定派生类型
引言
通常,当我们绑定派生类型(或派生类型集合)到 MVC View 时,它总是返回控制器上的实际基类型,因为我们的 Model(业务或领域实体)总是具有 BaseType
。为了保持派生类型(在回发期间),我们必须创建自己的自定义绑定器,实际上维护其派生类型。
这个提示包含一个将派生类型绑定到 MVC View 中基类型对象持久化的解决方案。
背景
我在我的项目中遇到了一个问题。 我有一个基类对象数组,其各个项目引用派生类对象。 我需要在我的 MVC View 中绑定这个数组,但在模型绑定方法中,它在回发时会丢失实际的派生类型。 因此,为了解决这个问题,我创建了一个自定义的 DerivedTypeModelBinder
,借助它,我能够保持派生类型绑定到基类对象。
Using the Code
我有一个基类 WarrantyBase
如下
[DataContract]
[Serializable]
[XmlInclude(typeof(AWarranty))]
[XmlInclude(typeof(BWarranty))]
[KnownType(typeof(AWarranty))]
[KnownType(typeof(BWarranty))]
public class WarrantyBase
{
}
以及其他的派生类如下…
[DataContract]
[Serializable]
public class AWarranty : WarrantyBase
{
}
[DataContract]
[Serializable]
public class BWarranty: WarrantyBase
{
}
然后我有一个基类数组,我需要在我的视图上绑定,如下所示
<% for (int i = 0; i < Model.Warranties.Count; i++)
{ %>
<tr>
<td>
<%= this.CheckBox(c => c.Warranties[i].IsSelected)%>
</td>
</tr>
当我在回发中获取我的模型时,我总是得到基类对象,而无法将这些基类对象转换为派生类。 因此,我需要一个解决方案,通过该解决方案,我的视图总是返回实际的派生类型,而不是基类型。 为了实现这一点,我需要编写一个 DerivedTypeModelBinder
,它派生自 DefaultModelBinder
,如以下代码片段所示。
public class DerivedTypeModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext,
ModelBindingContext bindingContext, Type modelType)
{
return base.CreateModel(controllerContext, bindingContext,
GetModelType(controllerContext, bindingContext, modelType));
}
protected override ICustomTypeDescriptor GetTypeDescriptor
(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var modelType = GetModelType(controllerContext, bindingContext, bindingContext.ModelType);
return new AssociatedMetadataTypeTypeDescriptionProvider(modelType).GetTypeDescriptor(modelType);
}
private static Type GetModelType(ControllerContext controllerContext,
ModelBindingContext bindingContext, Type modelType)
{
if (bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName + ".BindingType"))
{
modelType = System.Type.GetType(((string[])bindingContext.ValueProvider.GetValue
(bindingContext.ModelName + ".BindingType").RawValue)[0]);
}
return modelType;
}
}
然后,你必须使用一个隐藏控件来绑定视图中的实际类型,以便在回发期间保持相同。
<%= Html.Hidden(string.Format("Warranties[{0}].BindingType", i),
Model.Warranties[i].GetType().AssemblyQualifiedName)%>
然后,最后一步是在 Global.asax 文件中的 RegisterArea
或 RegisterRoute
方法中注册你的自定义绑定器。
// Register the binder in below place…
public override void RegisterArea(AreaRegistrationContext context)
{
RegisterAreaEmbeddedResources();
ModelBinders.Binders.Add(typeof(WarrantyBase), new Common.Helpers.DerivedTypeModelBinder());
}
结论
此解决方案解决了在视图中绑定基类对象并在回发中获取实际派生类对象的问题。