【问题标题】:Custom Model Binder does not fire自定义模型绑定器不触发
【发布时间】:2013-04-05 00:18:32
【问题描述】:

我已经在 global.asax 中为 MyList 注册了一个自定义模型绑定器。然而,模型绑定器不会为嵌套属性触发,对于简单类型它可以正常工作。在下面的示例中,它会为 Index() 触发,但不会为 Index2() 触发

Global.asax

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    ModelBinders.Binders.Add(typeof(MyList), new MyListBinder());

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
}

代码:

public class MyListBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        return new MyList();
    }
}

public class MyList
{
    public List<int> items { get; set; }
}

public class MyListWrapper
{
    public MyList listItems { get; set; }
}

public class TestController : Controller
{
    public ActionResult Index(MyList list)  // ModelBinder fires :-)
    {            
        return View();
    }

    public ActionResult Index2(MyListWrapper wrapper) // ModelBinder does not fire! :-(
    {
        return View();
    }
}

【问题讨论】:

  • 你找到解决这个问题的方法了吗?

标签: c# asp.net-mvc-4 model-binding


【解决方案1】:

模型绑定器用于允许操作接受复杂对象类型作为参数。这些复杂类型应该通过 POST 请求生成,例如,通过提交表单。如果您有一个无法被默认模型绑定器绑定的高度复杂的对象(或者它不会有效),您可以使用自定义模型绑定器。

回答您的问题: 如果您也没有为 MyListWrapper 类添加自定义模型绑定器,则不会在 GET 请求中调用 MyListBinder) 的 BindModel(,这就是 ASP.NET MVC 的工作方式。 但是,如果您通过添加带有 MyListWrapper 参数的 POST 操作来修改代码,则可以看到 BindModel 方法被正确调用。

[HttpGet]
public ActionResult Index2()  // ModelBinder doesn't fire
{
    return View();
}

[HttpPost]
public ActionResult Index2(MyListWrapper wrapper) // ModelBinder fires
{
    return View();
}

还有 Index2 视图

@model fun.web.MyListWrapper

@using (Html.BeginForm())
{
    @Html.HiddenFor(m => m.listItems)
    <input type="submit" value="Submit" />
}

如果您想“控制” GET 请求中的操作参数,您应该使用action filters。

【讨论】:

  • 在 POST 请求中,除非我为 MyListWrapper 添加活页夹,否则活页夹不会触发?
  • 我试过了,即使使用 MyListWrapper 的活页夹,在 GET 和 POST 请求中,MyListWrapper 活页夹都会被触发,但 MyListBinder 不会触发
  • 重点不是获取或发布,而是必须注册活页夹,否则 mvc 框架将不知道它......有几种方法来做到这一点,最好的方法是注册你的模型活页夹只是为了MyList 的单一数据类型...如其他答案中所建议的那样。
  • 我知道,最初的答案谈到了 GET 和 POST 请求之间的区别,我要指出的是,这两种方式都不起作用,所以没关系。
【解决方案2】:

您为 MyList 定义了 binder,因此仅当 action 方法输入参数的类型为 MyList 时才会触发。

ModelBinders.Binders.Add(typeof(MyList), new MyListBinder());

如果您希望模型绑定器即使在您的 MyList 嵌套到其他模型中时也能触发,您必须这样做:

[ModelBinder(typeof(MyListBinder))] 
public class MyList
{
    public List<int> items { get; set; }
}

然后,模型绑定器在遇到MyList 类型时触发,即使它是嵌套的。

【讨论】:

  • 不回答问题,要触发 Mylist 的模型绑定器,我不需要添加属性。当 MyList 是 MyListWrapper 的属性时,这是否会触发 Model Binder?
  • 给 WebAPI 用户的注意事项 - 使用自定义模型绑定器属性装饰嵌套模型的类将无法正常工作。我相信这与 WebAPI 如何使用格式化程序和反序列化请求正文有关,而 MVC 不使用格式化程序 WebAPI differences with MVC。
【解决方案3】:

将此添加到您的全局:

ModelBinders.Binders.Add(typeof(MyListWrapper), new MyListWrapperBinder());

然后创建一个可以处理绑定的 MyListWrapperBinder。

【讨论】:

  • 问题是当自定义类型是另一种类型的属性时触发它。
  • 底线是您需要一个 ModelBinder 用于传递给 ActionMethod 的任何类型。
【解决方案4】:

您的模型绑定器与您的 MyList 类匹配,而不是与 MyListWrapper。 MyListBinder 仅与 MyList 类或从 MyClass 继承的类一起使用。

【讨论】:

  • 请在问题下方添加 cmets,而不是作为答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-19
  • 1970-01-01
  • 1970-01-01
  • 2012-01-29
  • 1970-01-01
  • 1970-01-01
  • 2012-07-31
相关资源
最近更新 更多