简体   繁体   中英

Why can't I register a custom model binder for a List<int>?

I have an action that looks like

public ActionResult GetUsers(List<int> userIds) {//do stuff}

The list of userIds can become quite long, so I want to use Json.Net to deserialize it. To do so I created an IModelBinder implementation, which works fine for other objects, but never gets called for a List. The IModelBind looks like this

public class JsonBinder : System.Web.Mvc.IModelBinder
{
  public object BindModel(System.Web.Mvc.ControllerContext controllerContext, System.Web.Mvc.ModelBindingContext bindingContext)
  { //Do model binding stuff using Json.Net }
} 

And I register this model binder with this line

ModelBinders.Binders.Add(typeof(List<int>), new JsonBinder());

However the JsonBinder is never called. Why is this? Should I be using a ValueProvider?

Add the following event in global.asax (or add the code to your existing Application_BeginRequest handler):

protected void Application_BeginRequest()
{
    foreach (var type in ModelBinders.Binders.Keys)
    {
        System.Diagnostics.Trace.WriteLine(
                              String.Format("Binder for '{0}': '{1}'", 
                                             type.ToString(), 
                                             ModelBinders.Binders[type].ToString()));
    }

}

Then you can check in the VS output window what binders are currently registered. You could see something like this:

Binder for 'System.Web.HttpPostedFileBase': 'System.Web.Mvc.HttpPostedFileBaseModelBinder'
Binder for 'System.Byte[]': 'System.Web.Mvc.ByteArrayModelBinder'
Binder for 'System.Data.Linq.Binary': 'System.Web.Mvc.LinqBinaryModelBinder'
Binder for 'System.Threading.CancellationToken': 'System.Web.Mvc.CancellationTokenModelBinder'

You could also check if there is any ModelBinderProvider that could be selecting the binder provider, because the order for selecting which model binder is used is as follows:

  1. The attribute on the parameter of the action. See GetParameterValue method of the ControllerActionInvoker class

  2. The Binder returned from the IModelBinderProvider. See GetBinder method in the ModelBinderDictionary class

  3. The Binder globally registered in the ModelBinders.Binders dictionary.

  4. The Binder defined in the [ModelBinder()] attribute for the model type.

  5. The DefaultModelBinder.

Use a similar approach to check the model binder providers in the BeginRequest event:

foreach (var binderprovider in ModelBinderProviders.BinderProviders)
{
    System.Diagnostics.Trace.WriteLine(String.Format("Binder for '{0}'", binderprovider.ToString()));
}

Additionally, you could try to add Glimpse via nuget, as one of the tabs provides information about the model binder used for each of the parameters in the controller action.

Hopefully this will help you tracing why your model binder is not being used.

Have you tried using ModelBinder attribute in the action method?

public ActionResult GetUsers([ModelBinder(typeof(JsonBinder))] List<int> userIds)

Ref: https://msdn.microsoft.com/en-us/library/system.web.mvc.modelbinderattribute(v=vs.118).aspx

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM