MVC 5模型绑定器覆盖

时间:2016-03-23 17:39:42

标签: c# ajax asp.net-mvc

我写了一个Model Binder的覆盖。

public override object BindModel(Controller context, ModelBindingContext bindingContext)
{
    var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

    object returnVal = null;

    if (value == null)
        returnVal = base.BindModel(controllerContext, bindingContext);
    else
    {
        /* custom logic here that never seems to get called.
            returnVal = something();
        */
    }

    return returnVal;
}

我还有一个javascript服务(在Angular中)向我的一个控制器发出AJAX请求。

AJAX请求尝试发布一组int。我尝试单步执行模型绑定器,似乎value始终为null。通过一些魔术,base.BindModel()仍然能够将我的集合绑定到正确的C#对象。

问题在于我无法使用自定义绑定器,因为永远不会调用else块。除了使用ValueProvider之外,还有其他方法可以获得价值吗?

我也相信在此自定义绑定器正常工作之前(从内存中可能出错)。我最近从4.5更新到5.2.something。是否有任何更新可以改变这种行为?

2 个答案:

答案 0 :(得分:4)

  

我还有一个javascript服务(在Angular中)向我的一个控制器发出AJAX请求。

     

...

     

问题在于我无法使用自定义绑定器,因为从不调用else块。

  • 我将假设您已在一个或多个参数上全局或在操作本身上正确注册了活页夹。
  • 我还假设您的活页夹是在您预期的时候被调用的。

它为null,因为它无法根据您尝试绑定的模型名称查找数据。是否可以通过此名称找到该值取决于型号名称和客户端请求中发送的必须对齐/匹配的数据。但在任何人都可以告诉你为什么它不匹配的数据(包括你的模型与数组)可以通过以下三种方式之一从客户端发送:

  1. 如果使用该URL,您将在查询字符串中重复使用相同的属性名称。示例:?myArray=1&myArray=2&myArray=3。这意味着在您的模型绑定器中,您将不得不考虑这一点。
  2. 如果在POST中使用data(正文),那么它可能是一个实际的数组对象。 json中的示例:{"myArray":[1,2,3,4]}
  3. 您可能还会序列化整个表单并使用Angular发送它(可以让您更好地使用MVC中的绑定功能
  4. 因此,为了更好地回答您的问题,您需要提供

    1. 正在从浏览器发送数据的格式以及如何发送数据(查询字符串或数据有效负载)(这可能在您的Angular工厂,服务或控制器中)< / LI>
    2. 您尝试绑定到
    3. 的模型定义

      所以回顾一下:bindingContext.ModelName是预期的名称,必须与模型绑定器试图找到的数据相匹配。如果您要发送{"myArray":[1,2,3,4]},但您的模型属性名为ProductIds,那么它将始终为空。

        

      我最近从4.5更新到5.2.something

      不,不是我知道的。

      最后的想法。您还可以让默认模型绑定器执行,然后在类型匹配时使用返回值执行某些操作。如果绑定现在没有问题,但你想做一些后处理,这将是一个更好的选择。例如:

      public override object BindModel(Controller context, ModelBindingContext bindingContext)
      {
          var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
      
          object returnVal = base.BindModel(controllerContext, bindingContext);
      
          /* check returnVal and then additional custom logic here */.
      
          return returnVal;
      }
      

答案 1 :(得分:0)

请确保你做过这样的事情: -

  1. 自定义模型绑定: -

    public class HomeCustomDataBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(HomePageModels))
            {
                HttpRequestBase request = controllerContext.HttpContext.Request;
    
                string title = request.Form.Get("Title");
                string day = request.Form.Get("Day");
                string month = request.Form.Get("Month");
                string year = request.Form.Get("Year");
    
                return new HomePageModels
                {
                    Title = title,
                    Date = day + "/" + month + "/" + year
                };
    
                //// call the default model binder this new binding context
                //return base.BindModel(controllerContext, newBindingContext);
            }
            else
            {
                return base.BindModel(controllerContext, bindingContext);
            }
        }
    
    } 
    
  2. 一旦我们完成了自定义类的编码,我们需要在Application_Start()下的Global.asax中注册我所做的类。

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
        ModelBinders.Binders.Add(typeof(HomePageModels), new HomeCustomBinder());
    }
    

    3)最后,我们需要告知控制器我们希望它使用的绑定。我们可以使用属性[ModelBinder(typeof(HomeCustomBinder))]指定如下:

    [HttpPost]
    public ActionResult Index([ModelBinder(typeof(HomeCustomBinder))] HomePageModels home)
    {
        if (ModelState.IsValid)
        {
            ViewBag.Title = home.Title;
            ViewBag.Date = home.Date;
        }
        return View();
    }