DefaultModelBinder嵌套级别+其他绑定器的问题

时间:2010-02-16 14:23:57

标签: asp.net-mvc nested modelbinders defaultmodelbinder

我认为这是一种有点正常的情况,我需要将表单帖子绑定到“订单”模型。这个模型有几个层次的信息:

Order.Billing.FirstName
Order.Billing.Address.City
Order.Billing.Address.Country

使用DefaultModelBinder,如果我将表单发布到将此Order模型作为参数的操作,则以下字段为JustWork(TM):

<%=Html.TextBox("Billing.FirstName")%>
<%=Html.TextBox("Billing.Address.City")%>

此字段不会:

<%=Html.TextBox("Billing.Address.Country")%>

我的皱纹是乡村财产。在我们的例子中,Address.Country返回一个Country类实例(ISO2 / 3 / Name / Code逻辑)。它不是一个字符串。毫不奇怪,它默认不起作用。

我的第一个想法是创建一个CountryModelBinder(继承DefaultModelBinder)和ModelBinders.Binders。将它添加到Country类型。当我这样做时,CountryModelBinder永远不会在上面的场景中被调用。

我的第二个想法是创建一个AddressModelBinder(继承DefaultModelBinder)并将其绑定到我们的Address类型。虽然它被调用,但SetProperty对“Country”的调用具有空值,即使表单已发布名为“Billing.Address.Country”的字段。

经过一些修补,看起来模型绑定行为只在模型是动作所需的顶级类时调用CreateModel,而所有其他绑定器都为其子属性调用了BindPropery / SetProperty。

换句话说,如果我为Order,OrderAddress(Billing),Address和Country创建模型绑定器。对于接受订单的操作,仅调用OrderModelBinder.CreateModel。 ORderAddress和Address.BindProperty / SetProperty被调用用于某些事情,有时SetProperty值参数在显式发布在与其他字段属性映射匹配的名称中时为空。

只需向OrderModelBinder添加代码就可以将Billing.Address.Country拉出Request.Form。但是我有多个使用Address的模型,并且所有这些模型看起来都很糟糕。

我在这里缺少什么?有没有办法在这种情况下实际调用CountryModelBinder?我认为当Billing.Address.Country映射到Address binder的Country属性时,应该调用CountryModelBinder。

1 个答案:

答案 0 :(得分:0)

我已经尝试过你在这里所做的事情,显然在MVC3上,如果我为这种类型提供模型绑定器,它确实有效。

这只是一个概念证明,表明它可以工作,不应该被视为甚至接近生产级代码:

型号:

public class SimpleModel
    {
        public string Value { get; set; }
        public int Other { get; set; }
    }

    public class ComplexModel
    {
        public SimpleModel Complexity {get;set;}
        public string StrVal { get; set; }
    }

一些活页夹:

public class MBinder : IModelBinder
        {
            public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {
                if ( bindingContext.ModelType == typeof(SimpleModel))
                {
                    var simpleModel= new SimpleModel();
                    simpleModel.Other = 1;
                    simpleModel.Value = controllerContext.HttpContext.Request.Form["Complexity"];

                    return cm;
                }
                return null;
            }
        }

在全球的asax中:

ModelBinders.Binders.Add(typeof (SimpleModel), new MBinder());
视图中的

代码:

    @model ComplexModel

    @using ( Html.BeginForm() )
{ 
    <fieldset>
        @Html.LabelFor(x => x.Complexity)
        @Html.TextBoxFor(x => x.Complexity)
    </fieldset>

    <fieldset>
        @Html.LabelFor(x => x.StrVal)
        <br />
        @Html.EditorFor(x => x.StrVal)
    </fieldset>
    <input type="submit" />
}

控制器:

public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Index(ComplexModel model)
        {
            return RedirectToAction("Index");

        }
在MVC 3中BTW更好的选择是使用IModelBinderProvider接口,但我只是想展示一些可行的东西。