Model binding is a technique that allows you to map data to your controller actions in ASP.NET MVC. In the old days one would manually call
1 |
Request["param"] |
to get the value of а parameter, but this could quickly become annoying as you get many parameters (f.x., via form POST). Model binding abstracts away this tedious activity and allows us to focus on designing our controllers. The process itself looks like this:
A nice bonus is that we can map our models from any kind of request, for example a form POST or AJAX.
Model binding in ASP.NET MVC
Model binding is an essential concept of ASP.NET MVC, but yet people do not use it often. I guess this is due to the fact that many developers have been working with pure ASP.NET for long time where you usually access the query string via
1 |
Request |
. In MVC you should simply add an argument to the action method in your controller.
The model binding mechanism relies on the
1 |
DefaultModelBinder |
class, which is responsible for resolving the request type (is it JSON, XML or form POST), parsing it (with the help of value providers) and mapping it to the requested model.
When to use model binding
I use model binding for all requests to the controllers. Be it a GET or POST request, you can use model binding. This makes your controllers clear and focused on their presentation logic. A few examples when you can use this mechanism:
- Bind POST parameters to a model
- Bind query string to simple objects, for example, you can bind the search term to a string
- You have a query string parameter which is a serialized value of a complex object. Here you have two options: either bind it to a string argument and then manually deserialize it or, better in my opinion, create a custom model binder that does the deserialization for you and binds it directly to the custom model
You can actually use model binding for non-request mappings, for example when accessing value from the session. I use custom models to abstract away the session, current user, request URL, etc. This makes my controllers clear and simple. I try to avoid accessing directly the
1 |
Request |
,
1 |
Session |
or any other properties that each controller in ASP.NET MVC has (because it inherits from
1 |
Controller |
), because this makes my controller tightly-coupled and harder to test afterwards. Moreover, it makes my presentation logic simple and easy to follow by removing any dependencies on other properties. The controller uses only what it is supposed to use – either injected via the constructor or as an argument to the action method.
Implementing your own model binder
Although the built-in model binding mechanism will serve you fine in most cases, you may still want to implement custom logic for your application. You can easily achieve this by implementing
1 |
IModelBinder |
interface and register the model binder afterwards. This can happen in two ways:
- Decorate your model properties (or the entire argument of the action method) with
1ModelBinderAttribute
- Register it via
1ModelBinders.Binders
Registering your model binders via the model binders dictionary requires that you specify a model you will bind to. This means you have to specify all your model binders at application start, but in many situations you may want to be handle this dynamically. Moreover, it doesn’t give you much flexibility in terms of when you want to do the binding: you are forced to always provide the same binding to the same model type. To address these limitation, I have created a simple extension to the model binding mechanism.
You can define an interface,
1 |
IExtendedModelBinder |
, with these two methods –
1 |
CanBindModel |
and
1 |
BindModel |
.
1 2 3 4 5 6 7 |
public interface IExtendedModelBinder { bool CanBindModel(ControllerContext controllerContext, ModelBindingContext bindingContext); object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext); } |
Furthermore, you can inherit from
1 |
DefaultModelBinder |
, which as the name suggests is the default model binder, the following way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class DefaultExtendedModelBinder : DefaultModelBinder { private readonly IEnumerable _modelBinders; public DefaultExtendedModelBinder( IEnumerable modelBinders) { if (modelBinders == null) throw new ArgumentNullException("modelBinders"); _modelBinders = modelBinders; } public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { foreach(IExtendedModelBinder modelBinder in _modelBinders) { if (modelBinder.CanBindModel(controllerContext, bindingContext)) { return modelBinder.BindModel(controllerContext, bindingContext); } } return base.BindModel(controllerContext, bindingContext); } } |
The last thing is to replace the default model binder with our custom version. You can either explicitly create instances of all your extended model binders or use a dependency container to do this for you. I tend to do the latter.
1 |
ModelBinders.Binders.DefaultBinder = new DefaultExtendedModelBinder(...); |
Conclusion
Model binding abstracts away the tedious mapping logic for your models. It makes your controllers clear and devoted on your presentation logic only, which is to fetch data and create specific view models for your views.