Custom Model Binder in ASP.NET MVC

Posted by: Mahesh Sabnis , on 10/22/2016, in Category ASP.NET MVC
Views: 127187
Abstract: Using Custom Model Binding to map the data from the request to our ASP.NET MVC Model

In ASP.NET MVC, we can create our Models using Entity Framework, ADO.NET Code or any other data access techniques. While developing the Model layer, we declare Plain Old CLR Objects (POCO). If we use EntityFramework, then the application provides POCO objects which we can use as entities. The MVC controller provides action methods which access POCO objects as its input parameters and the action method uses this CLR objects to save to the database. ASP.NET MVC scaffolds Views with the help of POCO. During the scaffolding process, the Model Binder comes into picture. The Model binder is responsible to map View Elements (HTML helpers) to the POCO model properties. It is the model binder which acts as a bridge between the View and the MVC models.

 

Section 1: Model Binder in ASP.NET MVC

MVC uses following types for Model Binding:

IModelBinder interface - This defines methods that are required for a Model Binder, like the BindModel method. This method is responsible for binding a model to some values using ControllerContext and BindingContext.

IModelBinderProvider interface - This interface contains methods that enables dynamic implementation of model binding for classes which implement the IModelBinder interface. This is used to manage the custom binder for the type of data posted by the end-user in views.

DefaultModelBinder class

  • o This class is used to map a browser request to a data object. This class is a concrete request of the IModelBinder.
  • o This class is by default used by MVC for mapping the data send by the View elements to the POCO properties so that controller can use it for further processing.

The Model Binder can represented by the following diagram:modelbinder-mvc

Section 2: Implementing Custom Model Binders

We will use Visual Studio 2015 for implementing the application although you are free to use Visual Studio 2013 too.

Step 1: Create a new ASP.NET Web application of the name MVC_CustomModelBinder as shown in the following image

aspnet-mvc-project

Click on OK, this will show the following window, select Empty template and MVC checkbox as shown in the following image

mvc-empty-template

Step 2: Add a new Sql Server Database of name ApplicationDB.mdf. Keep this database empty. In the Models folder, add a new ADO.NET Entity Data Model of name ApplicationEntities. In the wizard, select Code-First from database as shown in the following image

ef-database-first

Select the ApplicationDB.mdf and finish the wizard. This will add ApplicationEntities.cs class file with ApplicationEntities class in it. This class is derived from DbContext class. We will use this class for performing Database operations.

Step 3: In the models folder, add a new class file of name Employee.cs with the following Employee class in it:

using System.ComponentModel.DataAnnotations;

namespace MVC_CustomModelBinder.Models
{
    public class Employee
    {
        [Key]
        public int EmpNo { get; set; }
        public string EmpName { get; set; }
        public decimal Salary { get; set; }
    }
}

The above Employee is an Entity class with EmpNo as primary key.

Since we need to generate table from this class, add the following line in ApplicationEntities class.

public DbSet<Employee> Employees { get; set; }

Step 4: Add a MVC controller in Controllers folder of name Employee Controller. In this controller, add the following action methods:

using System.Linq;
using System.Web.Mvc;
using MVC_CustomModelBinder.Models;
using System.Xml.Serialization;

namespace MVC_CustomModelBinder.Controllers
{
    public class EmployeeController : Controller
    {
        ApplicationEntities ctx;
        public EmployeeController()
        {
            ctx = new ApplicationEntities();
        }

        // GET: Employee
        public ActionResult Index()
        {
            var Emps = ctx.Employees.ToList();
            return View(Emps);
        }
        public ActionResult Create()
        {
            var empPostedData = new XmlSerializer(typeof(Employee));
            var Emp = (Employee)empPostedData.Deserialize(HttpContext.Request.InputStream);
            ctx.Employees.Add(Emp);
             
            return View("Index") ;
        } 
    }
}

The above code uses the ApplicationEntities object to communicate with the database. The Create action method is very important here. This uses an XmlSerializer class to define the type of XML data which will be received from the post request. Using the Deserialize() method, the request is read and stored in the Employee object which will be further used for database operations (skipped here). Put the break point on this method so that we can test it. To test the data, we will use fiddler tools (here Postman can also be used.)

 

Step 5: Open the Fiddler tool and use the following URL in the composer with the XML data as shown in the following image:

fiddler-tool

Run the MVC application.

Execute the call by clicking on the Execute button, the following debug result will be displayed in our Emp object declaration in code.

posted-data

The code is showing the Employee data posted. This is possible because of the Xml Deserializer method which is reading the request stream and mapping data to Employee object explicitly. We can use this for server-side processing. But as per the MVC controller Action methods, we should have a mechanism using which posted data should be auto-mapped with the CLR object. This is the place where ModelBinder comes into picture. In our case, we need to implement an infrastructure using which XML data posted will be mapped to the Employee object. We can do this using a Custom Model Binder.

Step 6: In the project add a new folder of name CustomModelBinders. In this folder add a class file with the following code.

using System;
using System.Web;

using System.Web.Mvc;
using System.Xml.Serialization;

namespace MVC_CustomModelBinder.CustomModelBinders
{
    public class XMLToObjectModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            try
            {
                //1.
                var model = bindingContext.ModelType;
                //2.
                var data = new XmlSerializer(model);
                //3.
                var receivedStream = controllerContext.HttpContext.Request.InputStream;
                //4.
                return data.Deserialize(receivedStream);
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.AddModelError("Error", "Received Model cannot be serialized");
                return null;
            }

        }
    }
    public class XMLToObjectModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(Type modelType)
        {
            //5.
            var receivedContentType = HttpContext.Current.Request.ContentType.ToLower();
            if (receivedContentType != "text/xml")
            {
                return null;
            }

            return new XMLToObjectModelBinder();
        }
    }

}

The XMLToObjectModelBinder class has the following specifications:

1. This statement reads the model type under the current model context.

2. The instance of the XmlSerializer is declared to work with the posted data.

3. The received data is read from the Post request.

4. The Received data is deserialized.

The XMLToObjectModelBindingProvider class implements IModelBinderProvider interface and implements its GetBinder() method. This method reads the content type from the incoming request. If the received content type is not text/xml, then null will be returned else an instance of XMLToObjectModelBinder will be returned.

Step 7: We will add the above custom model provider class in the application, so that application will load it in the model binder process. Open Global.asax and add the following line Application_Start() method. (highlighted)

protected void Application_Start()
{
    ModelBinderProviders.BinderProviders.Insert(0, new XMLToObjectModelBinderProvider());
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);
}

The ModelBinderProviders will add the binder providers in the application which we have created in the previous step.

Step 8: Change the code of the Create Action method in the EmployeeController class as shown in the following code (highlighted)

public ActionResult Create(Employee Emp)
{
    ctx.Employees.Add(Emp);
    ctx.SaveChanges(); 
    return View("Index") ;
}

Apply a breakpoint on the Create action method and run the application using Fiddler. Choose the same data as shown in Step 5.

The posted Employee data will be as shown in the following image:

emp-data

The code shows the Data is deserialized into the Employee CLR Object.

Conclusion

Custom Model Binder provides a mechanism using which we can map the data from the request to our ASP.NET MVC Model.

Download the entire source code of this article (Github)

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Mahesh Sabnis is a DotNetCurry author and a Microsoft MVP having over two decades of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions), and Front-end technologies like Angular and React. Follow him on twitter @maheshdotnet or connect with him on LinkedIn


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!