8

我有一个像下面这样的操作方法。

[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 的最佳方法是什么?

4

1 回答 1

2

我查看了 mvc DefaultModelBinder 实现的代码。绑定模型时,DefaultModelBinder 使用 GetModelProperties() 查找模型的属性。以下是 DefaultModelBinder 如何查找属性:

 protected virtual ICustomTypeDescriptor GetTypeDescriptor(ControllerContext controllerContext, ModelBindingContext bindingContext) {
            return TypeDescriptorHelper.Get(bindingContext.ModelType);
        }

TypeDescriptorHelper.Get 使用的是子类型 ModelType(在我的情况下为 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;
        }
于 2012-12-20T09:47:23.303 回答