How to use the ASP.NET MVC ModelBinder
One of the new features in the latest build of ASP.NET MVC is the ModelBinder, which is provided to allow Action methods to take complex types as their parameters. Previously, action methods were only able to take simple types such as strings and integers as their parameters. The new ModelBinder provides the facility to build complex types from component parts that (for example) may be part the result of submitting a form with several fields. To see an example of this in action, we will first need a fairly simple class to work with. The following class definition will typically be placed in the Models directory. I have left the using statements at the start of the file as an 'exercise for the reader'!
1: public class MBTest
2: {
3: public string Name { get; set; }
4:
5: public MBTest()
6: {
7: }
8: }
All fairly standard stuff. Now let's create a form on our index page that we can use to have a play with one of these objects:
1: <% using (Html.Form("Home", "About")) { %>
2: <input type="text" name="Name" />
3: <button type="submit">Submit</button>
4: <% } %>
Again, just the relevant form supplied here, and kept as simple as possible for clarity. Nothing in the routing needs to change: that will all happen just fine. Now, the aim is to write an Action Method that looks like the following:
1: public ActionResult About(MBTest testItem)
2: {
3: ViewData["Title"] = "About Page";
4:
5: return View();
6: }
Admittedly, this method doesn't actually do anything with the testItem object that it creates, but it could quite easily if it wanted to. What we want is that the Name property of testItem is populated with the contents of the text input field in our form. Previously, we would have done this by inserting code into the About method above to parse the results coming back. So here's the new bit. We create a helper class that will carry the knowledge of how to perform the translation from the form to the complex type. This class must implement the new interface IModelBinder.
1: public class MBTestBinder : IModelBinder
2: {
3: #region IModelBinder Members
4:
5: public object GetValue(ControllerContext controllerContext, string modelName, Type modelType, ModelStateDictionary modelState)
6: {
7: MBTest instance = new MBTest();
8: instance.Name = controllerContext.HttpContext.Request["Name"];
9: return instance;
10: }
11:
12: #endregion
13: }
Obviously this is a very simple example, and I haven't used most of the information passed to the GetValue method, but the intention of this post is primarily to be a starting point, just to get you 'up and running'. So the MBTestBinder class functions as a bridge, in a similar way to an ADO.NET DataAdapter. There's one final step to getting this all hooked up, and that's to tell the code to use MBTestBinder. This is done by applying the new ModelBinderAttribute to things. There are actually two different places you can use this attribute, with the same effect. The first is by decorating the model class:
1: [ModelBinder(typeof(MBTestBinder))]
2: public class MBTest
The second is decorating the parameter of your Action Method directly:
1: public ActionResult About([ModelBinder(typeof(MBTestBinder))]MBTest testItem)
My guess is that they've left the choice in because the decision about exactly where bridge classes such as MBTestBinder actually lives is not a straightforward one. Others will no doubt contribute much more involved examples and discuss whether this solution to the problem is even the correct one, but hopefully this post explains enough to enable people to get started with experimenting with it and getting a feel for it.