Binding in ASP.NET MVC
At my ASP.NET MVC + SOLID Principles talk in Cleveland last night, I had a couple of questions about binding in ASP.NET MVC. For instance:
- Can you still do something like <%= Bind(“Foo”) %> in your form?
- How does the controller that receives a POST get back the Model that was used in the form that was posted?
- Does it have to be serializable?
- What if I need to bind custom types to my Model class?
- Doesn’t having the Model referenced in the View eliminate the need for the Controller?
I answered these last night but I thought they were common enough as a theme that they deserved their own answers here as well.
Does ASP.NET MVC Support Two Way Binding via the Bind() Syntax?
No, not directly. Rather, you can use HTML Helpers to create your UI (if you like – you can also just hand code the HTML if that’s your preference – ASP.NET MVC is all about you being in control), and then use either the built-in or a custom ModelBinder to convert the POSTed data into your class/Model. More on ModelBinders below. The HTML helper syntax might look like this:
<%= Html.TextBox("Title", Model.Title) %>
If you don’t like the “magic string” used in this, you might look at Eric Hexter’s Input Builders project.
How does the controller that handles the POST get back the Model?
In my example last night, I had some code that looked like this (except it used a blog not a customer):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Customer customer)
{
// work with Customer here
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection formValues)
{
var customer = new Customer();
customer.FirstName = Request.Form["FirstName"];
customer.LastName = Request.Form["LastName"];
}
This gets old fast. A better method that is one step closer to the ModelBinder approach would be:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection formValues)
{
var customer = new Customer();
UpdateModel(customer);
}
This helper method automatically updates the properties of the object we pass into it with the values from incoming form parameters (using reflection to match up the property names with the form names). If we want to avoid dealing directly with the FormCollection in our controller, we can simply use the original signature I showed above, and have the controller take in as its parameter the model object (Customer in this case) that we want to have populated from the form.
If there are problems with the population of the model object, the ModelState.IsValid property will be false, and the ModelState will include details about the rule violations (such as a type mismatch). You can find more detail on this here.
Does the Model used for a controller that handles a POST need to be serializable?
No, it simply needs to have properties that can be mapped to the fields coming in from the POST. The class itself is never serialized or deserialized or sent over the wire. It’s simply mapped from the POSTed fields by a ModelBinder.
What if I need to bind custom types to my Model class?
In this case, you’ll want to write your own ModelBinder and register it so that ASP.NET MVC knows to use it when faced with a given type in your application. Writing a ModelBinder simply requires that you inherit from DefaultModelBinder and override the ConvertType() method. In order to register your type with its custom ModelBinder, you would do this:
// In Global.asax Application Start or an HttpModule
ModelBinders.Binders.Add(typeof(Customer), new CustomerBinder());
Here is a good example of writing a custom ModelBinder class.
Doesn’t having the Model referenced in the View eliminate the need for the Controller?
In response to seeing code in the View like this:
<%= ViewData.Model.FirstName %>
Someone asked if this was stepping on the responsibilities of the Controller, since the View was talking directly to the Model. Here there can be differing opinions. It’s not strictly required that you pass your Model classes to the View. You can simply pass in collections of strings via ViewData. Another common approach is to use a DTO (Data Transfer Object) or ViewModel (the “VM” in the MVVM palindrome pattern) which typically is a subset of one or more Model classes in your application that contains only the information necessary for a given View. It’s also not uncommon to pass your Model into the View. It’s a matter of preference and there are pros and cons to these approaches.
What is not recommended is for your Model (the Customer in my example here, which has a FirstName property) to be persistence aware and to magically go and fetch itself from the database when it is referenced by the View. The above code should only work if the Controller has explicitly passed in the Model to the View, using code like this:
public void View(int id)
{
Customer customer = customerRepository.GetCustomer(id);
return View(customer);
}
public class CustomerSummaryViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfLastPurchase { get; set; }
publi DateTiem AmountOfLastPurchase { get; set; }
}
...
public void Summary(int id)
{
Customer customer = customerRepository.GetCustomer(id);
Order order = orderRepository.List(id).Take(1); // gets most recent order
var summary = new CustomerSummaryViewModel() {
FirstName = customer.FirstName,
LastName = customer.LastName,
DateOfLastPurchase = order.DatePurchased,
AmountOfLastPurchase = order.Amount };
return View(summary);
}

13 Comments
Binding in ASP.NET MVC said
You've been kicked (a good thing) - Trackback from DotNetKicks.com
ASP.NET MVC Archived Buzz, Page 1 said
Pingback from ASP.NET MVC Archived Buzz, Page 1
Clay said
Thank you for the talk last night! I enjoyed it. I wanted to point out that in binding, blind reliance on automatic model binding can be a security threat.
This link titled "ASP.NET MVC - Think Before You Bind" explains some possible issues...
<a target="_blank" href="http://css.dzone.com/news/aspnet-mvc-think-before-you-bi">css.dzone.com/.../aspnet-mvc-thin</a>
New and Notable 330 said
Playing around quite a bit with jQuery while re-learning JavaScript. It's easy to see why people fall in love with it. WCF/WF Breaking All The Rules with WCF - Scott Hanselman reminds us that true Interop is hard even using WCF Metadata Client Behaviors
Binding in ASP.NET MVC : Steve Smith's Blog said
9efish.感谢你的文章 - Trackback from 9eFish
Haacked said
Regarding the question of "Doesn’t having the Model referenced in the View eliminate the need for the Controller?" I always point out that this doesn't mean the Controller is not needed because it's the controller that's responsible for handling the user input and handing the model to the view in the first place.
The view referencing the model is perfectly valid. See the diagram of the MVC pattern here: <a target="_blank" href="http://en.wikipedia.org/wiki/File:ModelViewControllerDiagram.svg">en.wikipedia.org/.../File:ModelViewC</a>
Typically, people forget that the "Model" is an application or presentation model, and not necessary a domain model (though for simplicity demos, I sometimes pass in a domain model).
Binding in ASP.NET MVC : Steve Smith's Blog said
Thank you for submitting this cool story - Trackback from DotNetShoutout
Arnis L. said
Are there any best practices for populating entities for controller action by id found in form nameValueCollection? So far it seems for me that there aren't much info about binding when it gets more complicated.
Daily tech links for .net and related technologies - June 11, 2009 said
Daily tech links for .net and related technologies - June 11, 2009 Web Development Opinionated Input
ssmith said
@Haacked,
Agree 100%. I covered in the talk the concept of using a "viewmodel" or "DTO" or presentation "model" - it's annoying that there isn't a single definitive term for "the model the UI needs to work with" as opposed to the domain model.
Daily Links for Friday, June 12th, 2009 said
Pingback from Daily Links for Friday, June 12th, 2009
ASP.NET MVC Stuff « QuantuMatrix’s Weblog said
Pingback from ASP.NET MVC Stuff « QuantuMatrix’s Weblog
Most Popular 2009 Posts said
If you’re one of my subscribers, you’re probably a software developer, or perhaps someone I know personally