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 は、partent 型 (私の場合は FormElement) である ModelType を使用しているため、子クラス (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 に答える