MVC Control Extensions - Automatically Set Control Names

To set a normal text box in the MVC framework, the most typical code would look like this:

<%=Html.TextBox("FirstName", ViewData.Model.Contact.FirstName)%>

The key here is that you should set the name of the textbox to be the exact same name of the property name.  If you do this, then it enables you to use extension methods such as the UpdateFrom() method to automatically populate your object from Request.Form parameters when you post to your controller action.  This is all well and good but it is very easy to make a typo when typing the "FirstName" string for example.  Wouldn't it be nice if this all just happened automatically?

Well, I found a very elegant solution to this last week when I was browsing the latest code of the Validation Framework on CodePlex.  In the MVC quick start code for the Validation Framework, they provide extension methods for creating a "ValidatedTextbox", for example, that works with that validation framework which looks like this:

<%=Html.TextBoxValidated(() => ViewData.Model.Product.ProductName)%>

Not only is this solution elegant but I quickly realized that this could be easily generalized to so many other scenarios.  Not just in the context of this validation framework but also for creating the most "normal" textbox scenario.  By using this method, I can now re-write the first example like this:

<%=Html.TextBox(() => ViewData.Model.Contact.FirstName)%>

The resulting HTML that is produced will populate the textbox with the value from the FirstName property and it will also name the textbox "FirstName".  So the HTML the gets rendered in the browser is:

It turns out that there is not many lines of code required to pull this off.  The lambda expression is specified in the mark up and a Linq Expression is used for the method parameter.  The complete code for the Textbox extension methods is as follows:

public static class ControlExtensions
    public static string TextBox<T>(this HtmlHelper htmlHelper, Expression<Func<T>> expression)
        return TextBox<T>(htmlHelper, expression, null);
    public static string TextBox<T>(this HtmlHelper htmlHelper, Expression<Func<T>> expression, object htmlAttributes)
        MemberExpression memberExpression = expression.Body as MemberExpression;
        if (memberExpression == null)
            throw new ArgumentException("The specified expression is not a valid MemberExpression.", "expression");
        Func<T> compile = expression.Compile();
        T value = compile.Invoke();
        return htmlHelper.TextBox(memberExpression.Member.Name, Convert.ToString(value), htmlAttributes);

Notice that since this is a MemberExpression where we're just getting a value from a property, we can simply use the Member.Name to get at the "FirstName" string.  And then we can use the Compile() method of the Expression class to get executable code in the form of a delegate that represents the lambda.  Now that we have the Func we can simply call Invoke() to get at the value of the FirstName property.  Now that we have the name and value, we can pass it to the already existing TextBox extension methods.

This technique can really be generalized to any MVC control.  It can also be generalized to create composite controls as they have done in the Validation Framework above.  In my opinion, Microsoft should consider including this type of thing in the base MVC library.  But if not, it's easy enough to add to your own MVC helper libraries.

Tweet Post Share Update Email RSS