我有一个如下所示的动作方法。
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Form newForm)
{
...
}
我有一个包含以下类的模型,我想从ajax JSON数据加载数据。
public class Form
{
public string title { get; set; }
public List<FormElement> Controls { get; set; }
}
public class FormElement
{
public string ControlType { get; set; }
public string FieldSize { get; set; }
}
public class TextBox : FormElement
{
public string DefaultValue { get; set; }
}
public class Combo : FormElement
{
public string SelectedValue { get; set; }
}
这是JSON数据。
{ "title": "FORM1",
"Controls":
[
{ "ControlType": "TextBox", "FieldSize": "Small" ,"DefaultValue":"test"},
{ "ControlType": "Combo", "FieldSize": "Large" , "SelectedValue":"Option1" }
]
}
$.ajax({
url: '@Url.Action("Create", "Form")',
type: 'POST',
dataType: 'json',
data: newForm,
contentType: 'application/json; charset=utf-8',
success: function (data) {
var msg = data.Message;
}
});
DefaultModelBinder正在处理嵌套对象结构,但它无法解析不同的子类。
使用相应的子类加载List的最佳方法是什么?
答案 0 :(得分:1)
我已经查看了mvc DefaultModelBinder实现的代码。绑定模型时,DefaultModelBinder使用GetModelProperties()查找模型的属性。以下是DefaultModelBinder如何查找属性:
protected virtual ICustomTypeDescriptor GetTypeDescriptor(ControllerContext controllerContext, ModelBindingContext bindingContext) {
return TypeDescriptorHelper.Get(bindingContext.ModelType);
}
TypeDescriptorHelper.Get正在使用ModelType,它是partent类型(在我的例子中是FormElement),因此不会检索子类(TextBox,Combo)的属性。
您可以覆盖该方法并更改行为以检索特定的子类型,如下所示。
protected override System.ComponentModel.PropertyDescriptorCollection GetModelProperties(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
Type realType = bindingContext.Model.GetType();
return new AssociatedMetadataTypeTypeDescriptionProvider(realType).GetTypeDescriptor(realType).GetProperties();
}
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
ValueProviderResult result;
result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".ControlType");
if (result == null)
return null;
if (result.AttemptedValue.Equals("TextBox"))
return base.CreateModel(controllerContext,
bindingContext,
typeof(TextBox));
else if (result.AttemptedValue.Equals("Combo"))
return base.CreateModel(controllerContext,
bindingContext,
typeof(Combo));
return null;
}