Model binding in mvc | Complete guide to MVC Programmers

Model-Binding-In-MVC

Model Binding in ASP.NET MVC

Model binding is the process of creating action method parameter objects using the data sent by browser in an HTTP request.

In this article we will understand following topics about model binding :

  • Creating example app
  • Model binding simple example
  • Using default model binder
  • Binding to complex type
  • Custom prefixes
  • Selective binding to arrays, collections
  • Manually invoke model binding

Creating Example App :

Create a new Web Application project in Visual Studio using empty template and checking the option to include the core MVC folders and references.

Create a class called Employee.cs in the Models folder having following content :

Contents of HomeController.cs file :

Create a view file Views/Home/Index.cshtml to support the Index action method in HomeController.cs file :

Create a Folder Views/Shared and add a view file _Layout.cshtml to it, the content of which are as following :

Model binding simple example :

Model binding is a bridge between HTTP request and the C# methods that define actions.

To see model binding at work start the example app and navigate to /Home/Index/1.

The result is as shown :

model binding simple demonstration

The URL contained the value of the PersonId property of the Person object I wanted to view, like this:

/Home/Index/1

The MVC Framework translated that part of the URL and used it as the argument when it called on the Index method in the Home controller class to service the request :

The process by which the URL segment was converted into the int method argument is an example of model binding.

Using Default Model Binder :

Binding to simple types :

If you start the application and navigate to /Home/Index/apple, figure shows the response from the server.

error processing model property

This is because default model binder tries to convert the value provided, apple to int, which causes error to generate.

You can fix this error by using nullable type and explicitely checking for null in action method.

Another way is to apply default parameter value in HomeController.cs file.

Binding to complex types:

When action method parameter is complex type, the DefaultModelBinder class uses reflection to obtain the set of public properties and then binds to each of them in turn.

To demonstrate how this works, I have added two new action methods to the home controller as shown :

Create a view CreateEmployee.cshtml to support CreateEmployee action method oveload without any parameter.

You can see how the action methods work by starting the app and navigating to /Home/CreateEmployee as shownn in figure :

using createemployee action methods

using createemployee action methods post

The default model binder discovers that the action method requires a Employee object and process each of the properties in turn.

For each simple type property, the binder tries to locate a request value, just as it did in the previous example. So, for example, when it encounters the EmployeeId property, the binder will look for a EmployeeId data value, which it finds in the form data in the request.

If a property requires another complex type, then the process is repeated for the new type. The set of public properties are obtained and the binder tries to find values for all of them.

A nested model class in Employee.cs

When looking for a value for the Line1 property, the model binder looks for a value for HomeAddress.Line1, as in the name of the property in the model object combined with the name of the property in the property type.

Creating Easily-Bound HTML :

The use of prefixes means that I have to design views that take them into account, although the helper methods make this easy to do.

In following code, you can see how I have updated the CreateEmployee.cshtml view file so that I capture some of the properties for the Address type.

Updating CreateEmployee.cshtml :

I have used the strongly typed EditorFor helper method, and specified the properties I want to edit from the HomeAddress property.

The helper automatically sets the name attributes of the input elements to match the format that the default model binder uses, as follows:

As a consequence of this feature, I don’t have to take any special action to ensure that the model binder can create the Address object for the HomeAddress property.

I can demonstrate this by editing the /Views/Home/Index.cshtml view to display the HomeAddress properties when they are submitted from the form, as shown :

Displaying the HomeAddress.City and HomeAddress.Country properties in the Index.cshtml File :

If you start the application and navigate to the /Home/CreateEmployee URL, you can enter values for the City and Country properties, and check that they are being bound to the model object by submitting the form as shown :

binding properties complex objects 1

binding properties complex objects 2

Specifying Custom Prefixes :

There are occasions when the HTML you generate relates to one type of object, but you want to bind it to another. This means that the prefixes containing the view won’t correspond to the structure that the model binder is expecting and your data won’t be properly processed.

To demonstrate this situation, I have created a new class file called AddressSummary.cs in the Models folder. You can see the contents of this file as following :

Adding new action method to HomeController.cs file :

I created the DisplaySummary.cshtml file in the /Views/Home folder.

To demonstrate the problem with prefixes when binding to different model types, I will change the call to the BeginForm helper method in the /Views/Home/CreateEmployee.cshtml file so that the form is submitted back to the new DisplaySummary action method.

Changing the Target of the Form in the CreateEmployee.cshtml File :

You can see the problem if you start the application and navigate to the /Home/CreatePerson URL.

When you submit the form, the values that you entered for the City and Country properties are not displayed in the HTML generated by the DisplaySummary view.

I can fix this by applying the Bind attribute to the action method parameter, which tells the binder which prefix to look for, as shown :

Now, you can see the problem is fixed when you start the app and navigate to Home/CreatePerson and click submit after filling form.

You can see city and country values are displayed due to changes we made in DispaySummary action method.

Selectively Binding Property :

Imagine country property in AddressSummary is sensitive and you don’t want the user to bind it.
You can achieve this by following code :

The Exclude property of the Bind attribute allows you to exclude properties from the model binding process.
Alternatively you can use Include property to only include certain properties in binding process as following :

Binding to arrays and collections :

Using default model binding you can bind the request data to arrays and collections.

Binding to arrays :

To demonstrate this I have added a new action method called Names to Home controller.

The Names method takes string array parameter names.

You can see the contents of Views/Home/Names.cshtml view file, which I created to show array binding :

The view displays different content based on the number of items there are in the view model. If there are no items, then I display a form that contains three identical input elements, like this:

When I submit the form, the default model binder sees that the action method requires a string array and looks for data items that have the same name as the parameter.

For this example, this means the contents of all of the input elements is gathered together to populate an array. You can see how the action method and view operate in Figure :

model binding arrays 1

model binding arrays 2

Binding to collections of custom model types :

You can also bind induvidual data properties to an array of custom type such as AddressSummary model class.
I have added a new action method to Home controller called address, which has strongly type collection parameter that relies on custom model class.

The view that I have created for this action method is the /Views/Home/Address.cshtml file :

This view renders a form element if there are no items in the model collection. The form consists of pairs of input elements whose name attributes are prefixed with an array index, like this:

When the form is submitted, the default model binder realizes that it needs to create a collection of AddressSummary objects and uses the array index prefixes in the name attributes to obtain values for the object properties.

The properties prefixed with [0] are used for the first AddressSummary object, those prefixed with [1] are used for the second object, and so on.

You can see the binding process when you run the app and navigate to /Home/Address URL as following :

binding collections custom objects 1binding collections custom objects 2

 

Manually Invoking Model Binding :

The model binding process is performed automatically when an action method defines parameters, but I can take direct control of the process if I want to.

This gives more explicit control over how model objects are instantiated, where data values are obtained from, and how data parsing errors are handled.

Following code demonstrates how I have changed the Address action method in the Home controller to manually invoke the binding process.

You can restrict the binding process to a single source of data. By default binder looks for four places :

  • form data
  • route data
  • query string
  • uploaded file

Restrinctig binder to formdata in the HomeController.cs file :

The built-in IValueProvider Implementations :

Source IvalueProvider Implementation
Request.Form FormValueProvider
RouteData.Values RouteDataValueProvider
Request.QueryString QueryStringValueProvider
Request.Files HttpFileCollectionValueProvider

Tip ■ There are other overloaded versions of the UpdateModel method that specify a prefix to search for and which model properties should be included in the binding process.

Dealing with Binding Errors Users will inevitably supply values that cannot be bound to the corresponding model properties—invalid dates or text for numeric values, for example.

When I invoke model binding explicitly, I am responsible for dealing with any errors.

As an alternative approach, I can use the TryUpdateModel method, which returns true if the model binding process is successful and false if there are errors, as shown in following code.

Using the TryUpdateModel Method in the HomeController.cs File :

The only reason to favor TryUpdateModel over UpdateModel is if you don’t like catching and dealing with exceptions. There is no functional difference in the model binding process.

Summary :

  • Model binding is the process of creating action method parameter objects using the data sent by browser in an HTTP request.
  • Use nullale type action paramaeter or default paramaeter value for action method to avoid error.
  • Model binding can be applied to complex types, arrays, collections.
  • Use custom prefixes when prefixes containing the view won’t correspond to the structure that the model binder is expecting.
  • Binding can be performed selectively for model properties using include, exclude in Bind attribute.
  • Manually invoking binding gives explicit control over how model objects are instantiated, where data values are obtained from, and how data parsing errors are handled.

Leave a Reply

Your email address will not be published. Required fields are marked *