Model binding is one of
the magic in MVC framework. We know that, if the model property is matches
exactly with view then MVC architecture automatically takes care the model
binding process. This is very simple and
straight forward.
But, if the model
property is not match exactly with the view ? Then how to bind model in time of
data submission?
In this article we will
understand to bind model when model property is incompatible with View. To
implement our custom model binding mechanism we have to use implement either IModelBinder
interface in our custom class or we can derive our custom class from DefaultModelBinder
class.
The DefaultModelBinder
class implement IModelBinder interface. So, let’s the definition of
IModelBinder . It contains only one method called BindModel and it takes two
parameters one is ControllerContext and the other is ModelBindingContext. Have
a look on below definition of IModelBinder.
public interface IModelBinder
{
// Summary:
// Binds the
model to a value by using the specified controller context and
// binding
context.
//
// Parameters:
//
controllerContext:
// The
controller context.
//
// bindingContext:
// The binding
context.
//
// Returns:
// The bound
value.
object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
}
Here is the diagram which showing that the DefaultModelBinder
class has implemented IModelBinder interface.
Now, let’s look the definition of DefaultModelBinder class.
The class contains many methods including BindMode() method. Have a look on
below screen, though it’s not full class definition. The BindModel() method is defined
as virtual method means we can implement the method in our own way.
Ok, let’s try to implement our custom model binding mechanism;
first we will implement IModelBinder class in our custom binder class.
So, let’s create one simple model class called Person and it
contains only two properties. The first property is name which will be
combination of three different property called “first_name” ,”middle_name” and “last_name”
which we will define in view.
namespace ModelBinder.Models
{
public class Person
{
[Required]
[MaxLength(50,ErrorMessage="Full
name should be within 50 character")]
public string full_name { get; set; }
[Range(18,80)]
[Required(ErrorMessage="Please
provide age")]
public Int32 Age { get; set; }
}
}
Here is the view which will be mapped with the Person mode. We
are seeing that there are three different properties which will construct full
name.
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
@{Html.BeginForm("PostData", "Customodelbinder");
<table>
<tr>
<td>First Name : </td>
<td>@Html.TextBox("first_name")</td>
</tr>
<tr>
<td>Middle Name : </td>
<td>@Html.TextBox("middle_name")</td>
</tr>
<tr>
<td>Surname :</td>
<td> @Html.TextBox("last_name")</td>
</tr>
<tr>
<td>Age:</td>
<td> @Html.TextBox("age") </td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" name="Save" value="Save" />
</td>
</tr>
</table>
}
</div>
</body>
</html>
Now, the fact is clear that, the property of model is not
mapped with property of View, then we have to write our own mapping logic to
bind the view data in model.
Create one class and implement IModelBinder interface within
it. In below snippet, we have created “PersonModelBinder” custom binding class
and implemented IModelBinder interface. We have seen that IModelBinder contains
only one method called BindModel and we have implemented the logic to map view
property with the model property.
public class PersonModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
string first_name = request.Form.Get("first_name");
string middle_name = request.Form.Get("middle_name");
string last_name = request.Form.Get("last_name");
int Age = Convert.ToInt32(request.Form.Get("age"));
return new Person { full_name = first_name + middle_name
+ last_name, Age = Age };
}
}
The implementation is very
simple, just we are combining first_name, middle_name and last_name to combine
full name and returning Person object accordingly.
Fine, now we will create the
controller which will contain PostData() action and as parameter , it will take
Person type object after binding in our custom PersonMModelBiner class. Here is
the simple implementation.
public class CustomodelbinderController : Controller
{
public ActionResult Index()
{
return View();
}
public void PostData([ModelBinder(typeof(PersonModelBinder))] Person person)
{
}
}
Now, we have to
register the custom binder class in MVC pipeline. Just add below line in global.asax page.
//Register
Custom Model binder
ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder());
Fine, we have setup everything to bind model using our
custom class. Let’s run the application and we should see below view.
I have given few arbitrary data and in controller we are
seeing that the first_name, middle_name and last_name property has combined
within single property called full_name.
Now, as we said, we can use DefaultModelBinder class too to
implement BineModel method, Just we have t override the method. Here is sample
implementation
public class PersonModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
string first_name = request.Form.Get("first_name");
string middle_name = request.Form.Get("middle_name");
string last_name = request.Form.Get("last_name");
int Age = Convert.ToInt32(request.Form.Get("age"));
return new Person { full_name = first_name + middle_name
+ last_name, Age = Age };
}
}
Border line:
In this article we have learned to implement custom model
binding when model property is not matched with the view. Hope it will help you
to understand the custom model binding.
Great
ReplyDelete