How do I create a custom model binder using the `BindModel(HttpActionContext actionContext...` signature?
Asked Answered
G

4

25

I need to know how to create a custom IModelBinder in MVC 4 and it has been changed.

The new method that has to be implemented is :

bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext);
Gearwheel answered 28/3, 2012 at 15:3 Comment(0)
H
28

There are 2 IModelBinder interfaces:

  1. System.Web.Mvc.IModelBinder which is the same as in previous versions and hasn't changed
  2. System.Web.Http.ModelBinding.IModelBinder which is used by the Web API and the ApiController. So basically inside this method you must set the actionContext.ActionArguments to the corresponding values. You no longer return a model instance.
Herzegovina answered 28/3, 2012 at 15:11 Comment(1)
There's also having to register a custom model binder. ASP.Net Web API doesn't have the same way as MVC3. Check out this post to see how to do it in MVC4 Beta. The bottom of the answer is tough to figure out, but note that you set it in global.asax.cs with GlobalConfiguration.Configuration.ServiceResolver.GetServices...Competency
F
24

This link, provided by Steve, provides a complete answer. I'm adding it here for reference. Credit goes to dravva on asp.net forums.

First, create a class derived from IModelBinder. As Darin says, be sure to use the System.Web.Http.ModelBinding namespace and not the familiar MVC equivalent.

public class CustomModelBinder : IModelBinder
{
    public CustomModelBinder()
    {
        //Console.WriteLine("In CustomModelBinder ctr");
    }

    public bool BindModel(
        HttpActionContext actionContext, 
        ModelBindingContext bindingContext)
    {
        //Console.WriteLine("In BindModel");
        bindingContext.Model = new User() { Id = 2, Name = "foo" };
        return true;
    }
}

Next, provide a provider, which acts as a factory for your new binder, and any other binders you may add in the future.

public class CustomModelBinderProvider : ModelBinderProvider
{
    CustomModelBinder cmb = new CustomModelBinder();
    public CustomModelBinderProvider()
    {
        //Console.WriteLine("In CustomModelBinderProvider ctr");
    }

    public override IModelBinder GetBinder(
        HttpActionContext actionContext,
        ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(User))
        {
            return cmb;
        }

        return null;
    }
}

Finally, include the following in your Global.asax.cs (e.g., Application_Start).

var configuration = GlobalConfiguration.Configuration;

IEnumerable<object> modelBinderProviderServices = configuration.ServiceResolver.GetServices(typeof(ModelBinderProvider));
List<Object> services = new List<object>(modelBinderProviderServices);
services.Add(new CustomModelBinderProvider());
configuration.ServiceResolver.SetServices(typeof(ModelBinderProvider), services.ToArray());

Now, you can just delare the new type as a parameter to your action methods.

public HttpResponseMessage<Contact> Get([ModelBinder(typeof(CustomModelBinderProvider))] User user)

or even

public HttpResponseMessage<Contact> Get(User user)
Fortyish answered 13/4, 2012 at 19:58 Comment(1)
I believe, as long as you explicitly use [ModelBinder(typeof(CustomModelBinderProvider))] in your action, you don't need the ModelBinderProvider.Antimissile
W
8

An even simple way to add a modelbinder without a ModelBinderProvider is this:

GlobalConfiguration.Configuration.BindParameter(typeof(User), new CustomModelBinder());
Watertight answered 13/2, 2013 at 14:48 Comment(1)
This worked perfectly! For whatever reason I could not get any of the other examples on this page to work with MVC4. The interface for ModelBinderProvider seems to have changed. But removing the ModelBinderProvider and adding this code to the Application_Start worked great!Kinzer
C
3

A post RC update to Todd's post:

Adding your model binder provider has been simplified:

var configuration = GlobalConfiguration.Configuration;

configuration.Services.Add(typeof(ModelBinderProvider), new YourModelBinderProvider());
Cowbird answered 13/9, 2012 at 12:13 Comment(1)
This worked for me. Is there any way to do this globally, i.e. set the default model binder?Hoo

© 2022 - 2024 — McMap. All rights reserved.