Published: 01 Jul 2011
By: Bipin Joshi
Download Sample Code

ASP.NET MVC model binding allows you to map HTTP request data with a model. This article discusses how model binding works for various types of models (simple types, complex types, collections etc.). It also shows how to create a custom model binder if situation calls for it.

Contents [hide]

Introduction

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 it.

NOTE

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

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 (Id, FirstName and 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

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 and collections.

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

Default binding 

for simple types

Figure 4 shows what happens if action method parameter name and form field name doesn't match.

Figure 4: Failed default binding due to name mismatch

Failed 

default binding due to name mismatch

Notice that the form field names are FirstName and LastName respectively whereas the action method names are changed to fname and lname respectively. Due to this mismatch the default binder cannot map the form data correctly and you get fname and 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 Id, FirstName and LastName properties.

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

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 properties, Street, Country and 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:

Notice the <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 Address. Further, Street, Country and 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

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

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:

The Example4() action method has two parameters of type IList, id and name. In 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 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.

Figure 9: Receiving form data as a list of Employee objects

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 ([0], [1], [2] 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 below:

Figure 10 shows the Employee objects received by the Example5() action method.

Figure 10: Multiple Employee objects received as a list

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 single method BindModel() that allows you to bind model with the form data. Let's see how you can do that with an example.

Consider a view shown in Figure 11 below:

Figure 11: Sample run for custom model binder

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:

The BindModel() method has two parameters viz. ControllerContext and 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 [ModelBinder] 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 binder:

Figure 12: Custom model binder in action

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 how.

Add another class and name it as EmployeeModelBinder2. Inherit this class from DefaultModelBinder base class and override BindProperty() method as shown below:

The 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 BirthDate properties whereas for FirstName and 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 Name. The 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 the job.

Summary

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 method using [ModelBinder] attribute. A custom model binder can also be specified in the Global.asax file using Binders collection.

<<  Previous Article Continue reading and see our next or previous articles Next Article >>

About Bipin Joshi

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.

Other articles in this category


Code First Approach using Entity Framework 4.1, Inversion of Control, Unity Framework, Repository and Unit of Work Patterns, and MVC3 Razor View
A detailed introduction about the code first approach using Entity Framework 4.1, Inversion of Contr...
jQuery Mobile ListView
In this article, we're going to look at what JQuery Mobile uses to represent lists, and how capable ...
Exception Handling and .Net (A practical approach)
Error Handling has always been crucial for an application in a number of ways. It may affect the exe...
JQuery Mobile Widgets Overview
An overview of widgets in jQuery Mobile.
Book Review: SignalR: Real-time Application Development
A book review of SignalR by Simone.

You might also be interested in the following related blog posts


Understanding the MvcRouteHandler and MvcHandler in ASP.NET MVC read more
ASP.NET 4.0 Dynamic Data and Many to Many Entity Framework Entities read more
Spec Explorer: A Model-Based Testing tool read more
MvcContrib working on Portable Areas read more
Silverlight, MVVM, Prism and More at VSLive Orlando read more
ASP.NET MVC 2 Preview 2 read more
RELEASED ASP.NET MVC 2 Preview 2 read more
Html Encoding Code Blocks With ASP.NET 4 read more
Presentation Models: Cohesion read more
5 Minute Overview of MVVM in Silverlight read more
Top
 
 
 

Discussion


Subject Author Date
placeholder verygood Johnson Yuan 11/7/2014 11:56 AM

Please login to rate or to leave a comment.