Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET MVC Custom Model Binder

0.00/5 (No votes)
22 Jun 2013 1  
MVC custom binding.

Introduction

In the example below I would like to break up the date into three fields: Day, Month, and Year, on my view, but I would like my model to have just one property that can store the combination of these fields.

Background

Recently I was looking at an unusual problem where we had to add custom fields to a view on an ad hoc basis. Not really a problem if it was an MVC app talking directly to a data source. But mine was over several REST based services that were talking to a CRM dynamics backend, spread across multiple domains. Which meant we had to change the data models through out the system. That's when it occurred to  me that we can have one dedicated field  that can store all the ad hoc field data using JASON or xml and we append it to one of the existing fields. Probably not the ideal solution, but that's when I came across custom binding for MVC. I would like to share with you how simple and easy it is to use custom binding to solve similar issues.

Using the Code

View 

In my view I am going to provision three fields for the date within my form.

<form id="Home" action="" method="POST">
    Day     <input id="Day" name="Day" value="" type="text" />
    Month   <input id="Month" name="Month" value="" type="text" />
    Year    <input id="Year" name="Year" value="" type="text" />    
            <input id="Submit" type="Submit" value="Submit" />
</form>

Model 

In my model I will only have one property for the three fields called a Date:

public class HomePageModels
{
    public string Title { get; set; }
    public string Date { get; set; }
}

Custom Binding  

The custom binding class needs to inherit form IModelBinder. Here we capture the current request and extract the Form fields individually. Then we can manipulate these fields any way we like. In this example as you can see I am adding them to a single property called Date.

public class HomeCustomBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, 
                            ModelBindingContext bindingContext)
    {
        HttpRequestBase request = controllerContext.HttpContext.Request;

        string title = request.Form.Get("Title");
        string day = request.Form.Get("Day");
        string month = request.Form.Get("Month");
        string year = request.Form.Get("Year");

        return new HomePageModels
                   {
                       Title = title,
                       Date = day +"/"+ month +"/"+ year
                   };
    }
} 

Alternatively if we do not want to implement  custom binding for each and every Model and Property in our application we can inherit from the DefaultModelBinder and override the BindModel method  as below

public class HomeCustomDataBinder : DefaultModelBinder
    {

        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(HomePageModels))
            {
                HttpRequestBase request = controllerContext.HttpContext.Request;

                string title = request.Form.Get("Title");
                string day = request.Form.Get("Day");
                string month = request.Form.Get("Month");
                string year = request.Form.Get("Year");

                return new HomePageModels
                {
                    Title = title,
                    Date = day + "/" + month + "/" + year
                };

                //// call the default model binder this new binding context
                //return base.BindModel(controllerContext, newBindingContext);
            }
            else
            {
                return base.BindModel(controllerContext, bindingContext);
            }
        }

    } 

Once we have completed coding our custom class we will need to register the class which I do in the Global.asax under Application_Start().

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    AuthConfig.RegisterAuth();
    ModelBinders.Binders.Add(typeof(HomePageModels), new HomeCustomBinder());
}

Controller

Finally we need to inform the controller as to the binding we want it to use. This we can specify using attributes [ModelBinder(typeof(HomeCustomBinder))] as below:

[HttpPost]
public ActionResult Index([ModelBinder(typeof(HomeCustomBinder))] HomePageModels home)
{
    if (ModelState.IsValid)
    {
        ViewBag.Title = home.Title;
        ViewBag.Date = home.Date;
    }
    return View();
}

Points of Interest 

While you could argue that we can achieve the same by manually capturing the requests inside the controller and manipulating how the property is populated, the idea behind using custom binding is to facilitate reuse and thus avoid manually wiring up views and models. 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here