ASP.NET MVC model binding allows you to map and bind HTTP request data with a model. Model binding makes it easy for you to work
with form data because the request data (POST/GET) is automatically transferred into a data model you specify. ASP.NET MVC
accomplishes this behind the scenes with the help of Default Binder. This article discusses how model binding works for various types
of models viz. simple types, class types and lists. It also shows how to create a custom model binder if situation calls for
Throughout the article you will be using ASP.NET MVC 3 and ASPX views.
Before you begin...
Before you begin working with the examples that follow, create a new ASP.NET MVC Web Application using Visual Studio. Add a
controller named Home in the Controllers folder. You will add various action methods to this Home controller class to illustrate how
model binding works. The views used by all of our examples simply deal with employee data such as employee ID, First Name, Last Name,
Address etc. To save us some time and space we won't discuss too much about creating these views. You can obtain the complete source
code from the code download accompanying this article.
No binding at all
Before you delve into the model binding, let's see how an ASP.NET MVC application can use form data without any model binding at
all. Consider a simple view as shown in Figure 1.
Figure 1: A simple view accepting employee details
To handle the data POSTed by the view, you need to create an action
method in the Home controller. The action method is shown below:
The Example0 action method makes use of Form collection to access employee details. As you can see it checks if any
values exist in the form collection using the Count property. Individual values are then accessed using form field names
LastName). A status message is put in the
ViewBag so that
view can notify the user about the operation. Since you are accessing the form collection directly there is no model binding as such.
This approach is bit raw and you should avoid it wherever you can. Figure 2 shows a successful run of the view.
Figure 2: Status message from ViewBag displayed to the user
Binding with simple types
The default model binding in MVC is handled by a DefaultBinder object. A model binder is a class that implements IModelBinder
interface. ASP.NET MVC provides the default implementation (System.Web.Mvc.DefaultModelBinder) that works with simple types, classes
Now let's see how the default binding works with simple types.
Add two action methods in the Home
controller as shown below:
The first version of the action method (without any parameters) takes care of the GET requests and the other version
(with parameters and marked with
[HttpPost] attribute) takes care of the POST requests. Notice the names of the
parameters of the
Example1() action method. It is important that you keep the parameter names same as the form field
names (see HTML markup from the view below).
If you don't then the mapping between a form field and action method parameter will not happen correctly and instead of
the actual value you will receive a default value for that parameter (e.g. 0 for integer fields, null for string fields and so on).
Figure 3 shows the Watch window showing the values of id, firstname and lastname parameters respectively.
Figure 3: Default binding for simple types
Figure 4 shows what happens if action method parameter name and form field name
Figure 4: Failed default binding due to name mismatch
Notice that the form field names are
LastName respectively whereas the action method names are changed to
respectively. Due to this mismatch the default binder cannot map the form data correctly and you get
lname parameter values as null.
Binding with class types
In the previous example you used one or more method parameters to receive the form field data. Though this approach works, it
becomes cumbersome when there are too many pieces of data being submitted. In such cases it is better to create a class that
encapsulates all the required information. This way your action method will have just one parameter. For example, instead of accepting
employee ID, First Name and Last Name as three separate parameters of the action method you can create an Employee class with required
properties and then code an action method like this:
The Employee class used by
the Example2() action method is a simple class with get and set public
properties. The following code shows the Employee class with
In this case, the default model binder automatically maps the form field names with the property names of the Employee
class and assigns the values accordingly. Figure 5 shows an Employee object as received in the action method with property values
assigned by the default binder.
Figure 5: Default model binder populates Employee object with form data
Binding with class properties
The default binding also takes care of properties that are class types. For example, the Employee class may have a property named
HomeAddress as shown below:
As you can see the
HomeAddress property is of type Address. The Address class in turn has three public
PostalCode and is shown below:
The View that accepts the data for the Employee class needs to follow certain naming conventions so that the
HomeAddress values are bound correctly. Have a look at the following HTML markup from the associated View:
<input> tags from the above markup carefully. These input elements have their name
attribute set in a specific way. Recollect that
HomeAddress is the property of the Employee class and is of type
PostalCode are the property names of the Address class.
Figure 6 shows the
HomeAddress property values populated by the default binder.
Figure 6: HomeAddress property mapped correctly by default binder
Binding with a list of simple types
In the preceding examples you were concerned with just one Employee at a time. At times you may need to work with multiple
"records" at a time. In such cases the data submitted by the view needs to be collected in a list or collection and then processed
further. Luckily, the default model binder provides an easy way for you to accomplish this. Let's see how.
Consider a view as
shown in Figure 7.
Figure 7: Submitting multiple “records” at a time
As you can see there is facility to submit three sets of values and
obviously you would like to receive them as three "records" in the action method. To make this work as expected you need to name the
form fields as shown in the following markup:
Notice the above markup carefully. You will find that all the
<input> elements accepting employee ID
are named as id and all the
<input> elements accepting employee name are named as name. Based on this naming
convention the default model binder considers all the values of the input elements with same name as a part of single collection. The
values can then be accessed in an action method as shown below:
Example4() action method has two parameters of type IList,
our specific example the id will hold three elements viz. E001, E002 and E003 and name will also hold three elements, Bob, Tom and
Jerry (see Figure 8).
Figure 8: Binding with list of strings
Binding with a list of class types
In the previous example you used list of strings to hold the form field values. You can also receive the values as a list of
Employee objects. However, you need to follow some specific naming convention for the form field names. Consider the view as shown in
Figure 9: Receiving form data as a list of Employee objects
The view allows you to specify Employee
details of multiple employees at a time. Now have a look at the following HTML markup from the above view:
The view is strongly typed and uses Employee class as its model. The
<input> elements use a
sequential index number ([
 and so on) for each Employee instance. Because of this
naming convention the default binder can pick all the values belonging to a specific index, assign to the corresponding properties of
an Employee instance and then add the Employee instance to a list.
The action method associated with the above view is shown
Figure 10 shows the Employee objects received by the
Example5() action method.
Figure 10: Multiple Employee objects received as a list
Dealing with arbitrary indices
Though the above example worked fine it can pose one problem. If the index numbers are not sequential then the values will not be
bound correctly. Such situation can arise when you delete some records using say jQuery and AJAX calls, causing index sequence to
break. In order to take care of this issue you need to supply an arbitrary index per employee record using a hidden form field. The
following HTML markup shows how this is done:
Notice the hidden form field
employees.Index whose value is set to any arbitrary index (100 in this case).
The text input fields then use
employees[<index_value>] format for name attribute. In this case even if the
indices are not sequential the default binder will map the data correctly with the help of the hidden index value.
Custom binding with a whole class type
So far you used the default model binder to map the form data fields with primitive types, class types and lists. In most of the
cases the default model binder will work just fine and you may not need anything else. However, in certain cases you may need to roll
out your own model binder. For example, your form fields and model properties may not have one-to-one mapping at all. You can take two
approaches if such need ever arises. You can either create a custom class that implements IModelBinder interface or you can create a
class that inherits from DefaultModelBinder class. In this section you will explore the first approach and the next section details
the second approach.
A model binder is a class that implements IModelBinder interface. The IModelBinder interface contains a
BindModel() that allows you to bind model with the form data. Let's see how you can do that with an
Consider a view shown in Figure 11 below:
Figure 11: Sample run for custom model binder
As you can see the Employee class now has an additional property –
BirthDate. Moreover, the value of the birth date comes from three HTML elements – two select elements and a textbox. In
other words there is no direct one-to-one mapping between form fields and Employee properties. Additionally, employee ID is entered
without "E" and you are supposed to add it automatically when a form is submitted. You will provide these additions with the help of a
custom model binder.
Add a new class to your ASP.NET MVC application and name it as EmployeeBinder1. Implement IModelBinder
interface in the EmployeeBinder1 class as shown below:
BindModel() method has two parameters viz.
ModelBindingContext and is responsible for binding the model. The
BindModel() method creates an instance
of Employee class and sets its properties by grabbing form data. Notice how
Request.Form collection is accessed using
HttpContext as supplied by the
ControllerContext parameter. Using the form data we construct a DateTime
instance and set the
BirthDate property. The prefix "E" is also added to the employee ID. Once the model is bound the
BindModel() method returns the
Employee instance. As you might have guessed this Employee instance will be
received by the action method under consideration.
When you rely on the default model binder you need not specify anywhere in
your code that you intend to use the
DefaultModelBinder class as a model binder. Now since you have created a custom
model binder you need to inform ASP.NET MVC about it. You can do that in the action method itself as shown below:
Notice the use of
[ModelBinder] attribute on the action method parameter. The
attribute specifies the type of the model binder class (EmployeeBinder1 in this case). This way MVC framework correctly invokes the
model binder to retrieve the value for the employee parameter. Figure 12 shows the employee object as bound by the custom model
Figure 12: Custom model binder in action
Custom binding with only few properties
In the preceding example you created a custom model binder for the whole class. Implementing IModelBinder interface requires that
you deal with the mapping of the whole model class on your own. What if you don't want to alter all of the form field values? What if
you wish to use the default model binding logic in your custom model? In such cases you can inherit the custom model binder class from
the DefaultModelBinder class and then you can bind some properties with a custom logic and others with the default logic. Let's see
Add another class and name it as EmployeeModelBinder2. Inherit this class from DefaultModelBinder base class and override
BindProperty() method as shown below:
BindProperty() method binds a property of the model and overriding it allows you to plug-in a custom
logic for binding one or more properties. In the above code you are using custom logic to bind Id and
properties whereas for
LastName properties the default logic as supplied by the
DefaultModelBinder class will be used. The
BindProperty() method receives ControllerContext, ModelBindingContext and
PropertyDescriptor parameters. The PropertyDescriptor parameter gives more information about the property being bound such as its
SetValue() method allows you to set value of a property under consideration after executing a custom logic.
For all other properties you can call
BindProperty() method on the base class.
The custom model binder created can
be specified in the action method using the
[ModelBinder] attribute as before.
Assigning model binders in Global.asax
In the preceding example you used
[ModelBinder] attribute to specify your custom model binder. If you are using the
custom binder in many controllers then it would be better to specify it at a central place. You can do that in the
Application_Start event inside the Global.asax.
If you are creating a custom model binder for a specific type
only (say Employee) then you can use the following line of code to inform MVC framework about it.
On the other hand if you have created a custom model binder by inheriting from the DefaultModelBinder base class and
would like to use the custom model binder as a default model binder throughout the application then the following line of code does
ASP.NET MVC model binding allows you to map HTTP request data with a model. This saves you from handing the raw request data
yourself. The inbuilt model binding capabilities stem from DefaultModelBinder class and take care of primitive types, class types and
collections. In certain cases you may need to create a custom model binder. This is accomplished by two ways viz. implementing
IModelBinder interface and inheriting from DefaultModelBinder class. Once created a custom model binder can be specified in an action
[ModelBinder] attribute. A custom model binder can also be specified in the Global.asax file using Binders
Bipin Joshi is a blogger, author and a Kundalini Yogi who writes about apparently unrelated topics - Yoga & Technology! A former Software Consultant and trainer by profession, Bipin is programming since 1995 and is working with .NET framework ever since its inception. He is an internation...
This author has published 7 articles on DotNetSlackers. View other articles or the complete profile here.
Please login to rate or to leave a comment.