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

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.

Written by Jonathan "JD" Danylko • Last Updated: • MVC •
HtmlHelpers help keep your Views clean

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):

  • If your web pages start to look like C# code, you might need an HtmlHelper.
  • If your web page is sprinkled with conditional statements (if..then..else), you might need an HtmlHelper.

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:

  • The class has to be static
  • The method has to be static
  • The method's first parameter in the signature must have the "this" declared.

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.

  • TagRenderMode.Normal - Used for a complete tag (opening and closing, i.e. <button></button>)
  • TagRenderMode.SelfClosing - This is used if you create any tags that are self closing like an <img /> or <br /> tags.
  • TagRenderMode.StartTag - Renders out a start tag (i.e. <button>)
  • TagRenderMode.EndTag - Renders out an ending tag (i.e. </button>)

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:

  • I was able to take conditional logic out of my views and display a different view based on a media type.
  • We off-loaded a LOT of programmatic HTML into their respective files so we don't have to recompile code at all. We just change each xxxxMedia.cshtml file and go about our business.

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:

  • Think Declaratively! - It's easier to modify HTML in a web page than to compile your HtmlHelper code.
  • Keep Database Code Out! - Don't make calls to the database from HtmlHelpers. This is definitely a no-no. It slows down your rendering process. That's why you have Controllers. They coordinate and collect all of the data and deliver it to your View. Do it in the controller.
  • Work With Your Model - When your data (ViewModel) is delivered to your View, it should have everything it needs for your HtmlHelper to render and return to your Views.
  • Keep Your HtmlHelpers small! - Your HtmlHelpers should act on an if..then and return back a MINIMAL amount of HTML.

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.

Did you like this content? Show your support by buying me a coffee.

Buy me a coffee  Buy me a coffee
Picture of Jonathan "JD" Danylko

Jonathan Danylko is a web architect and entrepreneur who's been programming for over 25 years. He's developed websites for small, medium, and Fortune 500 companies since 1996.

He currently works at Insight Enterprises as an Principal Software Engineer Architect.

When asked what he likes to do in his spare time, he replies, "I like to write and I like to code. I also like to write about code."

comments powered by Disqus