Learn how ASP.NET MVC helpers are a better solution for reusing chunks of HTML markup
If you introduce ASP.NET MVC to developers with a strong ASP.NET Web Forms expertise, they feel suddenly out of place because they can’t use server controls (at least, not with the same ease and comfort). Therefore, one of the first questions asked is "What alternate tools does ASP.NET MVC offer to create reusable pieces of markup to display in the browser?" All in all, you have two non-exclusive choices in ASP.NET MVC. You can use classic user controls (ASCX files) or HTML helpers.
You can successfully employ either approach to define layout and content of ASP.NET MVC views. But neither approach is perfect; both have pros and cons. With HTML helpers, you have to build any HTML markup you need using C# code. Most developers with ASP.NET expertise will find this difficult and will prefer taking a more traditional approach, such as using user controls. For rendering complex layouts, however, user controls are problematic in ASP.NET MVC. So the question is: "Is there a middle ground that allows developers to use the familiar HTML pattern while filling up views with HTML helpers?"
An HTML helper is an extension method attached to the HtmlHelper class. From within an ASP.NET MVC view you use an HTML helper through the Html property of the ViewPage class. The main purpose of any HTML helper is to act as a simple factory of HTML markup. Put another way, all an HTML helper does is prepare and emit HTML in the form of a string. Here’s how you use an HTML helper to emit all the markup required for an input tag:
<%= Html.TextBox("LastName") %>
The method TextBox extends the HtmlHelper class to add the capability of emitting a piece of HTML that renders as an <input> element. Here’s the internal structure of an HTML helper:
var builder = new StringBuilder();
// Accumulate HTML text into the string-builder object
As you can see, an HTML helper is centered on a string builder object where you buffer any HTML content you need. When you’re done you just return the resulting string. You might want to wrap the string in an MvcHtmlString object, if the content you're going to return is already HTML-encoded.
Being extensively code-based, an HTML helper requires that you build programmatically any HTML tree you need. This is not problematic as far as simple tags are concerned; however, when you try to build more complex HTML trees you might lose the HTML perspective of what you’re doing and not match C# instructions with actual HTML tags and attributes to generate.
The programmatic building of HTML trees is nothing new in ASP.NET. If you've written a custom server control, you know what I mean. A custom server control is an HTML factory that produces HTML markup based on the value of bindable properties. Internally, as a control author, you build the expected HTML tree using C# or Visual Basic code. Many ASP.NET developers are not familiar with the steps necessary to write a custom server control. So when these developers look into ASP.NET MVC, they are intimidated by having to produce a user interface using fluent code rather than graphic designers. Let’s put HTML helpers aside for a while and consider using plain old user controls in ASP.NET MVC.
ASP.NET User Controls
An ASP.NET user control is an .ascx file that defines a mini window of HTML markup to be integrated into the main view. The beauty of user controls is that they are reusable pieces of HTML written as a classic HTML page. If you feel comfortable with the HTML syntax, writing a user control is a piece of cake. Furthermore, you can enrich a user control with a collection of properties that you can set declaratively from within the source code of the view.
In ASP.NET MVC, user controls are classes that inherit from ViewUserControl or ViewUserControl<T>. User controls receive a reference to the view model object and can integrate values from the model in the layout. This can only be done using inline code blocks. Here’s an example:
<%= Model.CompanyName %>
How can you use a user control in an ASP.NET MVC view? You can do that in a couple of ways. First, you can reference a user control using a tag in much the same way you would do it in ASP.NET Web Forms:
<x:TableOfCustomers runat="server" ID="MyGrid" />
Second, you can resort to a wrapper HTML helper that renders the content of the specified user control. The wrapper HTML helper is RenderPartial. Here’s how to use it:
<% Html.RenderPartial("TableOfCustomers.ascx"); %>
Let’s suppose that the user control you’re using renders a grid of customer information. How would you pass the list of customers to the user control? An ASP.NET Web Forms developer might think of an approach that entails standard data binding. With this approach, you create an ad hoc property on the user control (say, DataSource) and then bind it declaratively to some data. Then you call the DataBind method from the Page_Load event of the code-behind class. Here’s an example:
<x:TableOfCustomers runat="server" ID="MyGrid" DataSource='<%# Model.Customers %>' />
This code would certainly work but it's deprecated in ASP.NET MVC. A better approach exists—and it's one that doesn’t require that you play with the data binding event of ASP.NET. The ViewUserControl class features an ad hoc property named ViewDataKey. It's a string property that tells the user control which key to pick up in the ViewData dictionary to fetch data. Interestingly enough, the property works even if you're not using the weakly typed ViewData collection for passing data from the controller to the view. If you’re using a strongly typed view model, the value stored in ViewDataKey is assumed to be the name of a public property on the view model object passed to the view. Here’s how to rewrite the previous code that references a user control:
<x:TableOfCustomers runat="server" ID="MyGrid" ViewDataKey="Customers" />
You no longer need data binding events and the user control will receive the content of the Customers property (if any) as defined on the view model data object. This code is fully equivalent to using RenderPartial to pass a view model object explicitly:
<% Html.RenderPartial("TableOfCustomers.ascx", Model.Customers); %>
The neat separation of concerns between request processing (namely, what the controllers do) and rendering of the view makes binding data to a user control an absolutely seamless process that's independent from the ASP.NET data binding machinery.
Contrasting HTML Helpers and User Controls
As long as you stick to the Web Forms view engine, using user controls or made-to-measure HTML helpers is nearly the same, at least from a functional point of view. In both cases, you can create and display reusable pieces of markup. However, some further differences exist if you consider what it takes to build a user control and an HTML helper.
You write an HTML helper using plain code; you write a user control by composing HTML literals and ASP.NET server controls. The layout of a user control is essentially static, compared to the flexibility you get from a regular programming language. An HTML helper is a real and extremely flexible HTML factory: You pass in some input values and the helper applies its hard-coded logic to return a string that evaluates to valid HTML markup. In other words, the helper builds its output programmatically, whereas a user control has a static layout that you can only flesh out with dynamically provided data. In addition, a user control is limited in the use it can make of server controls.
Let’s put it this way: if you choose user controls to build reusable HTML snippets, what would be the typical content of a user control? You can hardly use server controls because ASP.NET MVC doesn’t forward postback data during the page lifecycle. You could use server controls as plain HTML factories, but you'll have a problem passing data to the server control. This can be done only via data binding; and ASP.NET data binding requires that you have a code-behind class and call the DataBind method on the page object.
As you can see, usable user controls result from adapting legacy technology to a new context. If you think that using user controls would let you reuse much of your Web Forms skills, you’re only partially right. The typical user control employed by an ASP.NET MVC application is made of code blocks through which you express the logic that builds the expected user interface dynamically. Data passed in is simply merged with HTML literals to produce the final result.
In ASP.NET MVC, both user controls and HTML helpers can build HTML markup on the fly. HTML helpers do it using plain code; user controls use a mixed approach in which code blocks are interleaved with static chunks of HTML. This said, either approach is okay from a functional perspective.
If you don’t like the idea of producing HTML using C# code, then you can try producing HTML with user controls and code blocks inside the body of user controls. This approach is more than okay, if it works for you; if not, I’m afraid that HTML helpers are the way to go. Finally, notice that HTML helpers—more than user controls—help increase the readability of ASP.NET MVC views. But this, perhaps, is just a personal perspective.
The TagBuilder Object
Can you do anything to improve the maintainability of an HTML helper's source code? What scares many developers is that you produce HTML by composing pieces of text into a string. To partially remedy this, you can use the TagBuilder class. As the name suggests, the class builds an HTML tag. Here’s an example:
tag.Attributes\\["href"\\] = linkUrl;
To grab the markup for the specified tag, you just call the ToString method.
HTML helpers have a twofold purpose: They represent reusable chunks of HTML that you can build programmatically and in a quite flexible way and extensive use of HTML helpers make the view far easier to read and maintain. To maximize view readability, you should avoid using code blocks and introduce an HTML helper wherever and whenever you feel the need of some logic in the view.
This may lead to too much noise in the code because you might need two distinct (and quite simple) helpers that display a string in a different way. In this regard, you can achieve interesting results by employing template helpers. But that’s good fodder for another article.
Dino Esposito (firstname.lastname@example.org), an architect at IDesign, specializes mainly in ASP.NET, AJAX, and RIA solutions. Dino co-authored Microsoft .NET: Architecting Applications for the Enterprise (Microsoft Press) and is the author of Programming ASP.NET MVC 2 (Microsoft Press).