提问人:claco 提问时间:2/16/2010 最后编辑:tereškoclaco 更新时间:8/31/2013 访问量:956
嵌套级别 + 其他绑定器的 DefaultModelBinder 问题
DefaultModelBinder Problem with nested levels + other binders
问:
我有一种我认为有点正常的情况,我需要将表单帖子绑定到“订单”模型。此模型包含以下几个层次的信息:
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.Add 它到 Country 类型。当我这样做时,CountryModelBinder 永远不会在上面的场景中被调用。
我的第二个想法是创建一个 AddressModelBinder(继承 DefaultModelBinder)并将其绑定到我们的 Address 类型。虽然确实被调用了,但对“Country”的 SetProperty 调用有一个空值,即使窗体发布了一个名为“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 绑定器的 Country 属性时,应该调用 CountryModelBinder。
答:
我尝试过做你在这里做过的事情,似乎在 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 中,更好的选择是使用 IModelBinderProvider 接口,但我只是想展示一些可以工作的东西。
评论