HowTo: From the view to the controller in ASP.NET MVC with ModelBinders

image_thumb4With ASP.NET MVC the developer has now full control about the HTML rendering and how the form data will be transmitted to the server. But how can you get the form values on the server side? There are better ways in MVC to do that than Request.Form["..."].

Intro
If you are new to ASP.NET MVC, I recommend you to read this post or look at asp.net/mvc.

"Bindings"
In this HowTo you can learn how to access the form data in a more elegant way than Request.Form["..."].

Structure


image_thumb8

We have a "BindingController" and in the Model folder a "Person" class and 3 views:

- "CreatePerson" (form to create a person)
- "Result" of the action
- "Index" is the overview page

 

 

 

 

Person Class:

  1. public class Person  
  2. {  
  3.     public Guid Id { get; set; }  
  4.     public string Prename { get; set; }  
  5.     public string Surname { get; set; }  
  6.     public int Age { get; set; }  

Form in CreatePerson.aspx:

  1. <% using (Html.BeginForm()) {%>  
  2.  
  3.     <fieldset>  
  4.         <legend>Fields</legend>  
  5.         <p>  
  6.             <label for="Id">Id:</label>  
  7.             <%= Html.TextBox("Id") %>  
  8.             <%= Html.ValidationMessage("Id", "*") %>  
  9.         </p>  
  10.         <p>  
  11.             <label for="Prename">Prename:</label>  
  12.             <%= Html.TextBox("Prename") %>  
  13.             <%= Html.ValidationMessage("Prename", "*") %>  
  14.         </p>  
  15.         <p>  
  16.             <label for="Surname">Surname:</label>  
  17.             <%= Html.TextBox("Surname") %>  
  18.             <%= Html.ValidationMessage("Surname", "*") %>  
  19.         </p>  
  20.         <p>  
  21.             <label for="Age">Age:</label>  
  22.             <%= Html.TextBox("Age") %>  
  23.             <%= Html.ValidationMessage("Age", "*") %>  
  24.         </p>  
  25.         <p>  
  26.             <input type="submit" value="Create" />  
  27.         </p>  
  28.     </fieldset>  
  29.  
  30. <% } %> 

Binding: 1. Option – FormCollection:

  1. [AcceptVerbs(HttpVerbs.Post)]  
  2. public ActionResult FormCollection(FormCollection collection)  
  3. {  
  4.     Person person = new Person();  
  5.     person.Prename = collection["Prename"];  
  6.     person.Surname = collection["Surname"];  
  7.     person.Age = int.Parse(collection["Age"]);  
  8.     return View("Result", person);  

This option is the simplest possible way to access the form data, but not very elegant and hard to test, because you need to know which keys are in the FormCollection.

Binding: 2. Option- Parameter Matching:

  1. [AcceptVerbs(HttpVerbs.Post)]  
  2. public ActionResult ParameterMatching(string Prename, string Surname, int Age)  
  3. {  
  4.     Person person = new Person();  
  5.     person.Prename = Prename;  
  6.     person.Surname = Surname;  
  7.     person.Age = Age;  
  8.  
  9.     return View("Result", person);  

This option is very handy. The HTTP form values will be mapped to the parameters if the type and name are the same as the transmitted form value. This option is easy to test, but you have to map the parameters to your model manually.

Binding: 3. Option – Default Binding:

  1. [AcceptVerbs(HttpVerbs.Post)]  
  2. public ActionResult DefaultBinding(Person person)  
  3. {  
  4.     return View("Result", person);  

Now we use our own model as parameter type. The default model binder, which is included in the ASP.NET MVC, will map the incomming HTTP form values to the properties of our person, if type and name match.

Binding: 3. Option with addon – Default Binding with Include:

  1. [AcceptVerbs(HttpVerbs.Post)]  
  2. public ActionResult DefaultBindingWithInclude([Bind(Include="Prename")] Person person)  
  3. {  
  4.     return View("Result", person);  

You should think bevor you bind – to secure your applicaiton you can specify which properties will be mapped to the properties of the parameters.

Binding: 3. Option with addon – Default Binding with Exclude:

  1. [AcceptVerbs(HttpVerbs.Post)]  
  2. public ActionResult DefaultBindingWithExclude([Bind(Exclude = "Prename")] Person person)  
  3. {  
  4.     return View("Result", person);  

The same functionality, but this time reversed.

Binding: 3. Option with addon – Default Binding with Prefix:

image_thumb11

If you put a prefix in your Html Input controls (because you have multiple "name" fields), than you can specify a prefix.

All these options can be used together and you can map more than one parameter.

Binding: 4. Option – IModelBinder

If the values are getting more complex or you want your own mapping logic than you can use the IModelBinder interface. One example is Fileupload or to get the session user.

Now you just need to implement the IModelBinder interface:

  1. public class PersonModelBinder : IModelBinder  
  2.     {  
  3.         public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)  
  4.         {  
  5.          if (controllerContext == null) {    
  6.              throw new ArgumentNullException("controllerContext");    
  7.          }    
  8.          if (bindingContext == null) {    
  9.              throw new ArgumentNullException("bindingContext");    
  10.          }  
  11.  
  12.             NameValueCollection collection = controllerContext.RequestContext.HttpContext.Request.Form;  
  13.  
  14.             Person returnValue = new Person();  
  15.             returnValue.Id = Guid.NewGuid();  
  16.             returnValue.Prename = "Modelbinder: " + collection["Prename"];  
  17.             returnValue.Surname = "Modelbinder: " + collection["Surname"];  
  18.             int age = 0;  
  19.             int.TryParse(collection["Age"], out age);  
  20.             returnValue.Age = age;  
  21.  
  22.             return returnValue;  
  23.         }  
  24.  
  25.     } 

You get full access to the form values or other controller properties or route value.

You can register your Modelbinder global in the Global.ascx:

  1. protected void Application_Start()  
  2. {  
  3.     RegisterRoutes(RouteTable.Routes);    
  4.     ModelBinders.Binders[typeof(Person)] = new PersonModelBinder(); // Important!  

Everytime you have a parameter of type "Person" the "PersonModelBinder" will try to map the values to this object.

Or you can specify it per ActionMethod:

  1. [AcceptVerbs(HttpVerbs.Post)]  
  2. public ActionResult PersonModelBinder([ModelBinder(typeof(PersonModelBinder))] Person person)  
  3. {  
  4.     return View("Result", person);  

Lists/Array Binding:

You can even "bind" arrays / lists. Read Scott Hanselmans post for more information.

Screens:

image_thumb12

image_thumb14

image_thumb15

[Download Source Code]

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.

About the author

Written by Code Inside Team

Currently there is no additional info about this author.

5 Responses

  1. Great post! 

    Reply
  2. Nice post…

    Reply
  3. You can also bind with :
    Person person = new Person();
    UpdateModel(person);

    Reply

Comment on this post

Recent Posts

  • image1528-570x194_thumb.png
    Introduction to Redis on Windows & Redis usage with .NET

      Redis belongs to the NoSQL data banks and you will find it in the group of Key-Value Stores. Redis is often named “Blazing Fast” and according to the Stackoverflow Thread it is used to be two time (while writing) and three times (while reading) quicker than MongoDB. Even if the comparison is a little ...

  • Automated Security Analyser for ASP.NET websites

    Evil Hackers are lurking everywhere and many Web-applications are delicately and share “too much” with the attacker. A quick (first!) overview offers the Tool “ASafaWeb”. All the website does is making a few requests and writing an Analyses including problem solving’s. There are no permanent disadvantages (bad requests/ DoS attacks and so on). Example: KnowYourStack.com ...

  • image1489-570x194.png
    „Sign in with Twitter“ for your own ASP.NET WebApp

      “Sign in with Twitter” is a popular practice to authenticate the users on your website. One advantage compared to an own registration is the lower inhibition for the user. But on the other hand Twitter doesn’t fess up with all the information’s and you will get into a kind of addiction. At the end ...

  • image1485-570x194_thumb.png
    CodePlex is going to be updated

      CodePlex the Microsoft Open Source Project Hosting Plattform hasn’t changed that much in the last few years and for a few times I thought Microsoft stopped the whole developing process. But now I found out that there is still life in the project. Maybe it is because of the success of GitHub or because ...

  • image1474_thumb.png
    What does Adobe in the flash-free web? Magazine-Style Layouts with CSS Regions!

      Adobe is well known for Photoshop and Flash but of course there is a lot more. According to the “Future Post” from Google Adobe declared one of their big subjects on a Blogpost. I’m talking about the W3C Working Draft to CSS Regions. Adobe cooperates with the WebKit Team and W3C on this. What ...

Support us