ASP.NET MVC HtmlHelpers: Clean up your Views with HtmlHelpers

November 21st, 2014

Along with UrlHelpers, HtmlHelpers are useful when you want to introduce an if..then statement in your Views. In this post, we talk about what, when, why, and how to use HtmlHelpers with some additional quick tips.

After writing about UrlHelpers, I felt uneasy about not mentioning another method of keeping your Views clean: HtmlHelpers.

HtmlHelpers are used for taking conditional logic out of your Views and returning small sections of Html based on your model data.

So let's talk about HtmlHelpers, how to use them, and some advanced ways of optimizing them for your web pages.

What is an HtmlHelper?

Your Views should be considered "dumb" views meaning your HTML should contain no conditional logic AT ALL. It should be considered a template. All you are doing is dropping data on the web page.

There will be times where you'll start to sneak an if..then into your View. At this point, think about creating an HtmlHelper.

Like UrlHelpers, HtmlHelpers are merely extension methods and are easily recognizable in your Views by the "At" symbol (i.e. @Html, @Url).

They are extremely easy to build and can make your life (and views) a lot easier on you and your fellow developers.

When to use an HtmlHelper?

There are a number of developers I have encountered that write entire sections of code to produce HTML inside an HtmlHelper (Ahem...including me)

Umm...Don't do this.

"Then when do I use an HtmlHelper?"

Glad you asked. :-)

There are some general guidelines on when to use HtmlHelpers (we'll follow the "...you might be a redneck" mentality):

Now that you know when to use an HtmlHelper, let's focus on making one.

How to create an HtmlHelper

In ASP.NET MVC, one thing I noticed is that we don't have any buttons that we can declare in our web pages. Let's start there and create a Button HtmlHelper.

First, we need to know how to create an extension method.

Extension Methods are used to extend (hence the name) existing classes by attaching new methods to them. Extension Methods have the following characteristics:

So let's start making our HtmlHelper to demonstrate those 3 characteristics.

Helpers\Html\ButtonExtension.cs

using System.Collections.Generic;
using System.Web.Mvc;
 
namespace ThinController.Helpers.Html
{
    public static class ButtonExtension
    {
        public static MvcHtmlString Button(this HtmlHelper helper, string id, string name)
        {
            return helper.Button(id, name, null);
        }

        public static MvcHtmlString Button(this HtmlHelper helper, string id,             string name, IDictionary<string, object> attributes)         {             var buttonTag = new TagBuilder("button");             buttonTag.Attributes.Add("type", "button");             buttonTag.Attributes.Add("id", id);             buttonTag.Attributes.Add("name", name);             buttonTag.MergeAttributes(attributes);
            return MvcHtmlString.Create(buttonTag.ToString(TagRenderMode.Normal));         }     } }

Let's go over the code.

The reason for the overloaded method is because of the method parameters. If we don't want additional attributes, we can just call the button with an id and name. This is to make sure we don't duplicate code.

I know the 'this' declared in the method signature looks weird, but this is required and is an obvious clue that you are looking at an extension method. Ok, movin' on.

Next, we create the Button tag using the TagBuilder class, add the type to the tag, set our id and name, and finally merge in any attributes we define in the View.

Once we build our button, we need to render it. When ASP.NET MVC was first released, they returned String types. Now, it's a best practice to use an MvcHtmlString class to return the data as an HTML-encoded string.

Since the buttonTag is a TagBuilder, the ToString() is a little dfferent. You need to pass in a parameter of how the tag should be rendered.

In this case (for proper W3C standards), we'll just use the TagRenderMode.Normal.

When you want to use your new Button HtmlHelper in your web pages (View), use the following syntax:

@Html.Button("buttonId", "buttonName")

Easy, right?

A more advanced example

Let's say that you have a media object and you want a way to display the media's properties: height, width, filetype, and filesize. However, your media object can be an image, video, or text and you need to display this to the user.

An HtmlHelper is a perfect candidate for this type of logic.

Approach 1

I have been guilty of this approach and look back and cringe because I did it.

I created a LOT of TagBuilders that created the HTML programmatically. 200 lines of HtmlHelper code to create a one-liner in my HTML web page.

And no, I won't paste the code because 1). it's too long to show and 2). I'm too embarrassed. :-)

DO NOT get caught in this trap. It may seem powerful to make one call and pass in a parameter, but keep in mind, if the structure changes in the HTML, it'll be difficult to track down and trace.

Approach 2

After looking at this code and getting more gray hair, I realized that the HtmlHelper is the same class that performs other functions in your Views. The HtmlHelper uses the Partial method.

Since we are using an if..then..else and based on the items type, we can load different types of pages based on that media type.

Here is the final HtmlHelper:

public static class MediaHelper
{
    public static MvcHtmlString MediaSummary(this HtmlHelper helper, SiteMedia item)
    {
        if (item.IsImage()) return helper.Partial("ImageMedia", item);
        if (item.IsText()) return helper.Partial("TextMedia", item);
        if (item.IsVideo()) return helper.Partial("VideoMedia", item);
 
        return MvcHtmlString.Empty;
    }
}

How awesome is that?

There are two things we did here to optimize our code:

This was one of those moments when I felt the "rush of the code."

Mind. Blown.

One Final Thought...(ok, maybe four)

HtmlHelpers can be powerful, but can also cause distress by adding a lot of code to generate HTML.

Here are some thoughts about HtmlHelpers that I've learned over the years:

Conclusion

Your Views should be considered templates and HtmlHelpers assist in keeping them "dumb." However, you can get carried away with writing code to create a TON of HTML. Not a good idea. I've been stung by that trap as well.

It's kind of ironic that HtmlHelpers let you abstract Html into a coding form to take them out of your Views, but can be a  However, you can get carried away and continuously make a lot of TagBuilder classes.

HtmlHelpers are extremely powerful as long as you keep a balance between your code and HTML.

Do you have a different approach with HtmlHelpers? Let us know. Post your comments below.