Introduction
ASP.NET MVC has many great features. I have been playing around with
ASP.NET MVC,
and gone through couple of interesting things as part of Model Binding.
Here I am putting together all my findings, and explain with a simple
example. I am sure this will save a lot of time for people who are out
there, looking to understand, how exactly
ASP.NET MVC Model binding works.
In
ASP.NET MVC, Model Binding is, mapping the HTTP request data directly to
Action
method parameters and .NET objects (a Model).
Using the Code
As this is going big, I am splitting this into parts. In this part, I am covering
ASP.NET MVC object model binding, Parameter binding using Query String parameters, and controlling Model binding using Bind Attribute.
Below is the code structure:
To make it simple, and to concentrate more on Model binding, I am taking a simple example, which is having Employee Model, and
EmployeeController
Control, and two Views
EmployeeView1
,
EmployeeView2
.
When we run the above code, it displays Employee Add/Edit page (Adding/Editing to database is out of scope for this article),
EmployeeView1
view, like below:
'Using Query Strings' link is to demonstrate model binding using
Query String parameters, 'Control Model Binding' link is to demonstrate
how we can control model binding. Controlling Model Binding gives
control on what Model properties can bind with incoming HTTP request.
I have used VS 2008 SP1,
ASP.NET MVC 2 for this sample, recommended to use the same version.
Here is how model binding works, for e.g., consider the below request:
POST: Route Values, Query String Parameters
Route Values decide the controller and the Action method is
responsible for handling the request and the Query String Parameters
basically map to the Action method parameters, this is explained in
detail below. Here is the
Employee
Model:
public class Employee
{
[DisplayName("Employee ID")]
[Required(ErrorMessage = "ID Required")]
public int EmpId { get; set; }
[DisplayName("Employee Name")]
[Required]
public string EmpName { get; set; }
[DisplayName("Designation")]
[Required]
public string EmpDesignation { get; set; }
[DisplayName("Department")]
[Required]
public string EmpDepartment { get; set; }
[DisplayName("Salary")]
[Required]
public float EmpSalary { get; set; }
}
The above model is decorated with Data Annotations to take care of
simple validations. As part of this writing, we will not discuss much on
validations.
Binding Style 1: Query String Parameters
Query String Parameters can directly map to the Action method
parameters. Consider the below request which corresponds to the action
method in the sample.
EmployeeController.cs
-------------------------
public ActionResult UpdateQueryString(int EmpId, string EmpName,
string EmpDepartment, string EmpDesignation)
{
return View("EmployeeView1");
}
The above request directly maps each HTTP query
string
parameters
EmpId
,
EmpName
,
EmpDepartment
,
EmpDesignation
to Action method parameters respectively and updates the above
EmployeeModel
to contain these values. To observe this behavior, the attached sample renders the binded values in the
EmployeeView1
view page, once you set the source code, run the application from Visual Studio, and click on the link
Using Query Strings ; link. We will observe the updated fields on the view page. Have a look at the below snapshot.
We can generate the above HTTP request by using the
HtmlHelper
method like below. Observe the provided handy sample for more information.
<%= Html.ActionLink("Using Query Strings", "UpdateQueryString",
new { EmpId = 1, EmpName = "Nick", EmpDepartment = "IT",
EmpDesignation = "Director" })%>
Binding Style 2: Object Binding
We see this type of binding in Action methods most of the times. From
HTTP request values will be mapped to Model attributes behind the
scenes, to make it work we need to follow certain thumb rules. For e.g.,
consider the below code:
[HttpPost]
public ActionResult Update(Employee employee )
{
if (!this.ModelState.IsValid)
ModelState.AddModelError("Employee", "Model is Not Valid");
return View("EmployeeView1");
}
and the View page contains the following strongly typed way of rendering the fields. For e.g.:
<%= Html.TextBoxFor(model => model.EmpId) %>
The above code automatically binds the strongly typed '
EmpId
' entered in the text box to the
EmpId
of the model (employee) and sends over this to
Action
method
when we submit the form. Consider the below line, instead of strongly
typed method like above, we can consider using the below method:
<%= Html.TextBox("employee.EmpId")%>
Parameter name and property name combination pulls the values from HTTP input. The above method follows the
prefix.PropertyName
standard.
prefix
generally
if we don't specify, it will be Action parameter name. In the above
example, employee is the parameter for action method. Values entered in
the
EmpId
text box will be mapped to
EmpId
property of the Model.
If we specify the prefix using
Bind
attribute for the action method like below:
[HttpPost]
public ActionResult UsingPrefix([Bind(Prefix = "emp")]Employee employee)
{
if (!this.ModelState.IsValid)
ModelState.AddModelError("Employee", "Employee Not Valid");
return View("EmployeeView2");
}
then
Helper
method in the view page should look like below:
<%= Html.TextBox("emp.EmpId")%>
Click the submit button to observe the Object Model binding.
Controlling Model Binding
Sometimes, it may not be required to show all the fields in the View,
but Model contains more properties than what a View shows. It is a
potential candidate for injection attacks. To avoid this, we can control
the Model binding from View to Model using the
Bind
attribute.
public ActionResult BindInclude
([Bind(Include = "EmpId,EmpName", Exclude = "EmpSalary")] Employee employee)
{
return View("EmployeeView1");
}
Using the
Bind
attribute, we can white list Model Properties using
Include param name, black list Model Properties using
Exclude param name. In the above code, only
EmpID
,
EmpName
inputs
from HTTP request will be mapped to employee model, if this results in
invalid model state because of the validations set, then corresponding
validations will fire automatically. I will write in the next part,
about Collection binding, Collection binding objects, etc., how to do
manual Model binding. I am sure this reading will save a lot of time for
readers who are hunting for Model binding.
Disclaimer
This article uses a sample, which is not for direct production
deployment. This is to give the reader an idea on how model binding
works, it is individual responsibility to follow the necessary best
practices while implementing the Model Binding.