ASP.Net MVC Framework 2 - The Binding helper class (UI-mapper)

 

In this post I’m going to explain the use of the ASP.Net MVC Framework’s BindingHelperExtensions class and how to use it as what I call a UI mapper (map user input fields to an object). The BindingHelperExtensions has the following five methods:

T ReadFromRequest<T>(this Controller controller, String key)

string ReadFromRequest(this Controller controller, String key)

void UpdateFrom(Object value, NameValueCollection values)

void UpdateFrom(Object value, NameValueCollection values, string objectPrefix)

void UpdateFrom(Object value, NameValueCollection values, string[] keys)

I will not go deep into the ReadFromRequest method, but they can be used to get a value out from the Request object, such as a QueryString or Form field. They are also extensions method to the Controller class. In this post I will write about the UpdateFrom methods which can be used to easy map a View’s user input fields to an object.


Note: The UpdateFrom methods aren’t extension methods.


The UpdateFrom methods can be used inside of a Controller’s action method to update an object in the Model based on input values. For example if you have a Customer object and want to fill it with values out from the Request.From, you can do the following in your Controller:

Binding.UpdateFrom(customer, Request.Form);

In the examples in this post I will use an alias:

using Binding = System.Web.Mvc.BindingHelperExtensions;

I only use it to avoid using the name of the BindingHelperExtension class to get access to the UpdateFrom methods.

The UpdateFrom will see if there is an input field in the Request.Form collection with the same name as the property of the object passed as an argument. If there is a match, the value from input filed will be set to the value of the object’s property with the same name. For example if you have an input filed like this:

<input type="text" name="CompanyName" .../>


And if the Customer object you pass to the UpdateFrom method has a property with the same name; the value from the CompanyName field will be set to the Customer’s CompanyName property. If you have a View like this:

<input type="text" name="CompanyName" />
<input type="submit" name="City" value="Create"/>


The value of the submit button will be set to the Customer object if it has a property with the name City. So be careful what name you set to the input elements. This can of course be handled by using one of the other two UpdateFrom methods. For example the UpdateFrom that takes a objectPrefix as an argument, can be used to pass in a prefix of the input field names which should be collected from the values argument and be set to the value argument.

void UpdateFrom(Object value, NameValueCollection values, string objectPrefix)


For example if you have input fields that you want to belong to a specific object in the Model, you can use an object prefix like this:

<input type="text" name="Customer.CompanyName" />
<input type="text" name="Customer.ContactName" />
<input type="text" name="Product.Description" />

Note: You can also use "_" to sepereate the prefix from the property name "Customer_CompanyName".

When you use the UdateFrom method and you only want to map the values from the input fields with the prefix Customer to a Customer object passed to the UpdateFrom, you simply pass the “Customer” as an objectPrefix to the UpdateFrom method:

Binding.UpdateFrom(customer, Request.Form, "Customer");


The UpdateFrom will now only collect fields with the prefix “Customer”, and the names after the prefix will be mapped to properties of the Customer object with the same name. By using object prefix you can simply categorize input fields to be mapped to different objects. The last UpdateFrom method you can use is the one that takes an array of keys as an argument.

void UpdateFrom(Object value, NameValueCollection values, string[] keys)


By passing a string array with keys, only the specified keys will be collected from the values argument collection and be set to the value object’s properties. By using keys and pass a Request.Form to the values argument you can decide which input fields you want to collect.


Note: The values argument of the UpdateFrom takes an object of type NameValueCollection, so you pass for example pass the Request.Params collection if you want to get values from both QueryStrings and Forms. You can also pass your own NameValueCollection as you probably already have figured out ;)

To end this post I will give you a simple example how to use the UpdateFrom and with LINQ to SQL to create a new Customer to the Northwind database.

public class CustomerController : Controller
{
    private NorthwindDataContext dbc = new NorthwindDataContext();

    public void Index()
    {
       RenderView("Customer");
    }

    public void New()
    {
      Customer customer = new Customer();

      Binding.UpdateFrom(customer, Request.Form, "Customer");

      dbc.Customers.InsertOnSubmit(customer);
      dbc.SubmitChanges();
    }
}

Customer.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Customer.aspx.cs" Inherits="MvcUpdateInsertExample.Views.Customer.Customer" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>
</head>
<body>
    <div>
        <form action="Customer/New" method="post">
        
        Company name: <input type="text" name="Customer.CompanyName" /><br />
        Contact name: <input type="text" name="Customer.ContactName" /><br />
        
        <input type="submit" value="Create"/>
        
        </form>
    </div>
</body>
</html>

I hope this post gave you some brief understanding about how you can use the BindingHelperExtensions class to easy handle user input and map it to an object in the Model.

11 Comments

  • Hello Fredrik,

    I cannot understand why the second parameter is the NameValueCollection type.

    Fields in Html/ASPX page should have an unique ID, like properties in a Type (unique Name).

    The NameValueCollection collection stores multiple string values under a single key. IMHO I believe that a StringDictionary is more correct for this scenario, because you cannot have multiple values for a specific type/property.

    What's your opinion?

    Best Regards,

  • Hi Fredrik,
    What about the reverse of this..Is there a way to set all the form field values without DataBinding each individual input control?


  • Israel Ace:
    Actaully several HTML input fields can have the same name, one example are checkboxes. This is from the W3C:
    "Several checkboxes in a form may share the same control name. Thus, for example, checkboxes allow users to select several values for the same property. The INPUT element is used to create a checkbox control."
    If you have several fields with the same name and use Request.Form to request a value, all the values of the fields with the requested name will be returned as a comma seperated string. It's exactly how the NameValueCollection also work.


  • Jake Scott:
    If you use standard INPUT elements in the View, you can't access them from the server-side. So you need to add server-side script block into the field to set the values, for example:
    &lt;input type="test" value="&lt;%= ViewData.CompanyName%&gt;" .../&gt;

  • Ok, very good, however what about type checking in the binder. Currently it looks like the binder simply ignores type errors and returns no indication that a problem has occured. Which means that before you can do any binding at all you would have to check the form fields to ensure the correct TYPE of data was submitted. Ok, only int's , dates and other would need checking.

  • How do you handle situations where the form is inside a content page?
    I am getting "ctl00$MainContent$Length" as the key for the length input.

    Thanks,
    Chris

  • I have a question about dynamically generated forms. Hypothetical situation: You have a form where a registered member of your website has a list of friends, and each friend can have a phone number stored with them. You have a page where all friends are listed and their phone numbers are in text boxes next to their names. The number of friends can vary from member to member... How would you go about using the binding helper to get values from an unknown number of fields? Is there a way to handle it if the text boxes have unique names? Do you have to name them all the same and parse the list yourself on the server side?

  • Very useful indeed, thanks alot Scott.

    I have a question, how can you take data from the a view into a field without having declared a parameter to the method.

    e.g.

    the view is set to recognise all product objects (this is in the view code)

    public partial class Add : ViewPage

    View html:

    Product Name:



    Controller:

    public void SaveProduct()
    {
    try
    {
    String ProductName = ...

    here how can i get this productName value that is entered into the textbox from the form?

  • Sorry i meant Fredrik not Scott

  • how i bind dropdownlist from mvc ?

  • I want to pass a value in a textbox from a view to a controller and I want to retrieve that value at the controller.
    Help me in doing it.

Comments have been disabled for this content.