Model Binding And Custom Model Binding in ASP.NET MVC

Model Binding is one of the best features in ASP.NET MVC framework. ModelBinder maps http requests from view data to the model. The MVC runtime uses Default ModelBinder to build the model parameters. This is done automatically by MVC Model Binder.

Let us understand by a simple example how model information is passed to the controller by model binding from view in MVC.

Let us see a simple action.

  1. public ActionResult Index()  
  2.      {  
  3.          return View();  
  4.      }  
We have a model named StudentViewModel as below,
  1. public class StudentViewModel  
  2.   {  
  3.     
  4.       public int StudentId { getset; }  
  5.       public string Name { getset; }  
  6.       public string Address { getset; }  
  7.   
  8.       public string City { getset; }  
  9.       public string State { getset; }  
  10.   
  11.   
  12.       public string Country { getset; }  
  13.       public string Department { getset; }  
  14.   
  15.       public int Marks { getset; }  
  16.   }  
The index views returns to us an Index view, and we have the Index.cshtml as below,
  1. @model CustomModelBinding.Models.StudentViewModel  
  2.   
  3. @{  
  4.     ViewBag.Title = "Index";  
  5. }  
  6.   
  7. <h2>Index</h2>  
  8.   
  9.   
  10. @using (Html.BeginForm())  
  11. {  
  12.   
  13.     @Html.EditorForModel("StudentViewModel")  
  14.     <input type="submit" value="save" />  
  15. }  
  16.   
  17. @section Scripts {  
  18.     @Scripts.Render("~/bundles/jqueryval")  
  19. }  
We have a submit button and when we click the submit button we are calling an Index action.

When we run the index view we get the view as shown below in the screen.

 
We can pass the data in different ways, some of the options are,

Option 1: FormCollection

  1. [HttpPost]  
  2.  public ActionResult Index(FormCollection frm)  
  3.  {  
  4.      Var StudentId= studentformcollection["StudentId"].ToString();  
  5.      var studentName = studentformcollection["Name"].ToString();  
  6.      var studentAddress = studentformcollection["Address"].ToString();  
  7.   
  8.      var studentCity = studentformcollection["City"].ToString();  
  9.      var studentState = studentformcollection["State"].ToString();  
  10.   
  11.      var studentCountry = studentformcollection["Country"].ToString();  
  12.      var studentDepartment = studentformcollection["Department"].ToString();  
  13.   
  14.      var studentMarks = studentformcollection["Marks"].ToString();            return View();  
  15.  }  
 
We can also pass the model directly instead of using FormCollection.

Option 2: QueryString

Another way to get the data is by using Request.querystring as below which is the earlier version of asp.net.

var studentName = Request.QueryString["Name"].ToString();

Option 3: Giving the parameter directly

We also can directly pass the parameter by giving the parameter directly.

  1. [HttpPost]  
  2.         public ActionResult Index(int StudentId, string Name, string Address, string City,      string State,string Country, string Department, int Marks)  
  3.         {  
  4.             return View();  
  5.         }  
code

In the MVC framework normally the model contains all the fields which match that of views. Sometimes in the application the property of the ViewModel class or Entity Class property or Database field does not map correctly as per the UI Page. Let us consider the Address field in Database is a single field, but in the UI Page it is a combination of three fields: House No, Street Name, Locality etc.

The Name field in a Database is a single field but in the UI page it is three fields: First Name, Middle Name and Last Name.

Some of you may have the idea that we will concatenate the fields in controllers and assign it to a model property and entity class property to match exactly in the Database. It is not a good way of doing it. MVC has custom model binding which we will define once, and that logic will be applied wherever we want to refer to the Model.

If we have many places we have to use this scenario we have the feature in MVC called Custom Model Binding which makes it easier.

Let us see this in a simple example.

We have UI fields and ViewModel class which has different mappings but we need to map it using custom model binding and save it into database using entity framework.


Let us create a Database named student and create a table called studentInfo.

studentInfo

SQL Query for creating this table is,
  1. USE [Student]    
  2. GO    
  3.     
  4.     
  5. SET ANSI_NULLS ON    
  6. GO    
  7.     
  8. SET QUOTED_IDENTIFIER ON    
  9. GO    
  10.     
  11. CREATE TABLE [dbo].[StudentInfo](    
  12.     [StudentId] [intNOT NULL,    
  13.     [Name] [nvarchar](50) NULL,    
  14.     [Address] [nvarchar](50) NULL,    
  15.     [City] [nvarchar](50) NULL,    
  16.     [State] [nvarchar](50) NULL,    
  17.     [Country] [nchar](10) NULL,    
  18.     [Department] [nchar](10) NULL,    
  19.     [Marks] [intNULL,    
  20.  CONSTRAINT [PK_StudentInfo] PRIMARY KEY CLUSTERED     
  21. (    
  22.     [StudentId] ASC    
  23. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]    
  24. ON [PRIMARY]    
  25.     
  26. GO    

We will create a stored procedure to insert the student Information,

  1. USE [Student]  
  2. GO  
  3. /****** Object:  StoredProcedure [dbo].[InsertStudentInfo]    Script Date: 6/24/2016 10:40:58 AM ******/  
  4. SET ANSI_NULLS ON  
  5. GO  
  6. SET QUOTED_IDENTIFIER ON  
  7. GO  
  8.   
  9. CREATE PROCEDURE [dbo].[InsertStudentInfo]   
  10.      @StudentId [int],   
  11.       @Name   [nvarchar](50),  
  12.        @Address  [nvarchar](50),   
  13.        @City  [nvarchar](50),  
  14.        @State  [nvarchar](50),  
  15.        @Country  [nchar](10),  
  16.        @Department  [nchar](10),  
  17.        @Marks  [int]  
  18. AS  
  19. BEGIN  
  20.       
  21.     SET NOCOUNT ON;  
  22.   
  23.      INSERT INTO dbo.StudentInfo(StudentId, Name,Address,City,State,Country,Department,Marks )  
  24.     VALUES(@StudentId, @Name,@Address,@City,@State,@Country,@Department,@Marks)  
  25.   
  26. END  

Now our stored procedure is ready and we will use this stored procedure to insert records using entity framework.

Now we will create a simple ASP.NET MVC Web Application. Go to Visual Studio and create a new project.



In the next step select MVC and click OK.
 


Now we will create a New Item to fetch the Data using entity framework.

Go to the project Add new item,



Select ADO.NET Entity Data Model and Click Add. In the Next step we will get the below screen,



Select Generate from database and then click Next.

 

In this step choose your database server name and database name in this wizard.

Here in this step select the stored procedure option and select “InsertStudentInfo” which we created to insert into Database. Then Click Next.



Click Next to go to the next step,



Now we will see that the StudentEntities is created for us .In the Next step click Finish.

Now we will create the model .Go to the Model folder and add a new Model named StudentViewModel as below.

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.ComponentModel.DataAnnotations;  
  4. using System.Linq;  
  5. using System.Web;  
  6.   
  7. namespace CustomModelBinding.Models  
  8. {  
  9.     public class StudentViewModel  
  10.     {  
  11.        
  12.         public int StudentId { getset; }  
  13.         public string Name { getset; }  
  14.         public string Address { getset; }  
  15.   
  16.         public string City { getset; }  
  17.         public string State { getset; }  
  18.   
  19.   
  20.         public string Country { getset; }  
  21.         public string Department { getset; }  
  22.   
  23.         public int Marks { getset; }  
  24.     }  
  25. }  
For Creating the custom model Binding we need to write a class inheriting DefaultModelBinder and override the BindModel () method on it. BindModel() method takes two parameters of the class; ControllerContext and ModelBindingContext, out of which ControllerContext keeps the request information from being passed from view. We will get the request information from request query string, concatenate it, and assign it to our Model as below.
  1. public class StudentModelBinder : DefaultModelBinder  
  2.     {  
  3.   
  4.         public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)  
  5.         {  
  6.             if (bindingContext.ModelType == typeof(StudentUIModel))  
  7.             {  
  8.                 HttpRequestBase request = controllerContext.HttpContext.Request;  
  9.   
  10.                  int frmStudentId = Convert.ToInt32(request.Form.Get("StudentId").ToString());  
  11.                  string frmAddress = request.Form.Get("Address");  
  12.                  string frmCity = request.Form.Get("City");  
  13.                  string frmState = request.Form.Get("State");  
  14.   
  15.                 string frmFName = request.Form.Get("FName");  
  16.                 string frmMName = request.Form.Get("MName");  
  17.                 string frmLName = request.Form.Get("LName");  
  18.   
  19.                 string frmDoorNo = request.Form.Get("DoorNo");  
  20.                 string frmStreetNo = request.Form.Get("StreetNo");  
  21.                 string frmAreaName = request.Form.Get("AreaName");  
  22.   
  23.                 string frmCountry = request.Form.Get("Country");  
  24.                 int frmMarks = Convert.ToInt32(request.Form.Get("Marks").ToString());  
  25.   
  26.                 return new StudentUIModel  
  27.                 {  
  28.                     StudentId = frmStudentId,  
  29.                     Address = frmDoorNo + " " + frmStreetNo + " " + frmAreaName,  
  30.   
  31.                     City = frmCity,  
  32.                     State = frmState,  
  33.                     Name = frmFName + " " + frmMName + " " + frmLName,  
  34.                     Country=frmCountry,  
  35.                     Marks= frmMarks  
  36.                 };  
  37.   
  38.                
  39.             }  
  40.             else  
  41.             {  
  42.                 return base.BindModel(controllerContext, bindingContext);  
  43.             }  
  44.         }  
  45.   
  46.     }  

We will register this class to global.asax.cs as below to apply this model binding to all the places of the application.

  1. public class MvcApplication : System.Web.HttpApplication  
  2.  {  
  3.      protected void Application_Start()  
  4.      {  
  5.          AreaRegistration.RegisterAllAreas();  
  6.          FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);  
  7.          RouteConfig.RegisterRoutes(RouteTable.Routes);  
  8.          BundleConfig.RegisterBundles(BundleTable.Bundles);  
  9.          ModelBinders.Binders.Add(typeof(StudentUIModel), new StudentModelBinder());  
  10.      }  
  11.  }  
 
Let us go to the controller and get this model binding called from the controller Action.

First when the page is loaded we call the action Index, 

  1. public ActionResult Index()  
  2.   
  3. {  
  4.   
  5. return View(new StudentUIModel());  
  6.   
  7. }  

When the Index action is executed the Index view is rendered as below.



When we fill the Data and post the Data, In the Home Controller we have an action called Student Information which gets the request when the view is posted.

StudentInformation action passes the Model to the ModelBinder which does the custom Model Binding.

  1. [HttpPost]  
  2.         public ActionResult StudentInformation([ModelBinder(typeof(StudentModelBinder))] StudentUIModel studentmodel)  
  3.         {  
  4.   
  5.             try  
  6.             {  
  7.                 var name = studentmodel.Name;  
  8.   
  9.                 StudentEntities s = new StudentEntities();  
  10.                 s.InsertStudentInfo(studentmodel.StudentId, studentmodel.Name, studentmodel.Address,  
  11.                     studentmodel.City, studentmodel.State, studentmodel.Country, studentmodel.Department, studentmodel.Marks);  
  12.   
  13.                 ViewBag.InsertMessage = "Record Inserted";  
  14.             }  
  15.             catch(Exception ex)  
  16.             {  
  17.   
  18.             }  
  19.   
  20.             return View("Index");  
  21.   
  22.         }  

Now we are calling the InsertStudentInfo() method of StudentEntities which inserts data to the Table StudentInfo using our stored procedure.



We see our record is inserted in the Database. Observe the Name and Address field. It has all the data which we have appended from model binder.

There are places where we want to show the user different fields to enter the day, month, year and time and the database has a single field to save it. There are some places where  we want to add or append some text to the fields based on the current culture, or show a different currency symbol based on the current culture before the account balance in the UI fields.

I hope you understood the model binding and how to do custom model binding in MVC. Thanks for your valuable time for reading it.