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

cla*_*aco 7 asp.net-mvc nested defaultmodelbinder modelbinders

我有我认为是一种有点正常的情况,我需要将表单帖子绑定到"订单"模型.该模型具有以下几个级别的信息:

Order.Billing.FirstName
Order.Billing.Address.City
Order.Billing.Address.Country
Run Code Online (Sandbox Code Playgroud)

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

<%=Html.TextBox("Billing.FirstName")%>
<%=Html.TextBox("Billing.Address.City")%>
Run Code Online (Sandbox Code Playgroud)

此字段不会:

<%=Html.TextBox("Billing.Address.Country")%>
Run Code Online (Sandbox Code Playgroud)

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

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

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

一些修修补补之后,看来当模型的顶层类动作的人,而其他所有的粘合剂都要求孩子自己的属性BindPropery /的SetProperty模型绑定行为只要求CreateModel.

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

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

我在这里错过了什么?有没有办法在这种情况下实际调用CountryModelBinder?我认为当Billing.Address.Country映射到Address绑定器的Country属性时,应该调用CountryModelBinder.

Lin*_*ron 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; }
    }
Run Code Online (Sandbox Code Playgroud)

一些粘合剂:

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;
            }
        }
Run Code Online (Sandbox Code Playgroud)

在全球 asax 中:

ModelBinders.Binders.Add(typeof (SimpleModel), new MBinder());
Run Code Online (Sandbox Code Playgroud)

视图中的代码:

    @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" />
}
Run Code Online (Sandbox Code Playgroud)

控制器:

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

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

        }
Run Code Online (Sandbox Code Playgroud)

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