Patrick Desjardins Blog
Patrick Desjardins picture from a conference

Inline Razor Helper instead of Html Helper for you Asp.Net MVC WebSite

Posted on: 2014-04-08

In Asp.Net MVC you have two ways to create code that can be reusable within your page, or editor template or display template. Asp.Net MVC call these reusable mechanim Helpers. You can create Html Helper or Razor Helper. They are both generating Html but in a different way. The first one is independant of any rendering engine, while the second one use only Razor. One comes with several helpers already created for you, like Html.ActionLink, Html.LabelFor, Html.EditorFor when the second one does not have any developed for you. However, the last one can use the first one. This is not true the other way around.

Let see the first one, Html Helper. It is more popular than the other one. It is coded in C# (of VB.Net) and is in fact an extension to HtmlHelper. You just have to create a static class with a static method that extend System.Web.Mvc.HtmlHelper. Here is a small example.

 using System.Web.Mvc;

namespace TestHtmlHelper.HtmlHelper { public static class MyCustomHtmlHelper { public static MvcHtmlString MyFirstHelper(this System.Web.Mvc.HtmlHelper htmlHelper) { return new MvcHtmlString(" Test

"); } } } 

If you want to use this extension, you just have to use the @Html keyword in any of your view or template.

 @using TestHtmlHelper.HtmlHelper <div>@Html.MyFirstHelper()</div> 

This will render :

 <div> Test </div> 

This is not impressive, but in fact, these helper can be very useful when you specify a property, like for @Html.TextBoxFor(model=>model.MyDate). This can use reflection to get the display name which can be added in the helper to create a label to add it or to check the type to render something depending of the property type. It goes beyond just outputing static Html.

Let's create a simple Html Helper that take a object in parameter where we can sepecify which property to display. We will do something simple that set the name of the property into an header tag and its value inside a paragraph.

 namespace TestHtmlHelper.HtmlHelper { public static class MyCustomHtmlHelper { public static MvcHtmlString MyFirstHelper(this System.Web.Mvc.HtmlHelper htmlHelper) { return new MvcHtmlString("

Test

"); }

public static MvcHtmlString YourGenericHelperFor<TModel, TProperty>(this HtmlHelper htmlHelper, Expression<Func<TModel, TProperty>> expression) { ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); var propertyName = metadata.PropertyName; var value = metadata.Model; return new MvcHtmlString(string.Format("<h1>{0}</h1><p>{1}</p>", propertyName, value)); } } } 

As you can see, the Html Helper does not know about how the model class is made from. It just knowns that it takes by parameter an expression where we will get by reflection the property and its value. The use of this method is like the TextBoxFor Html helper.

 @model TestHtmlHelper.Models.MyModel @using TestHtmlHelper.HtmlHelper <div>@Html.MyFirstHelper()</div> <div>@Html.TextBoxFor(d => d.Name)</div> <div>@Html.YourGenericHelperFor(d => d.Name)</div> 

The result is previsable as you can see:

<div> Test</div> <div><input id="Name" type="text" name="Name" value="This is a test name" /></div> <div> <h1>Name</h1> This is a test name</div> 

Before going into the Razor Html Helper, you can see that inside the Html Helper I am concatenating string to have my end result. This is only possible in simple scenario. Otherwise, it becomes a mess. This is why you can use Html classes to help you rendering your output. In fact, the Html Helper we just created should be coded this way:

 public static MvcHtmlString YourGenericHelperPropertyConstructedFor<TModel, TProperty>(this HtmlHelper htmlHelper, Expression<Func<TModel, TProperty>> expression) { //Get values var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); var propertyName = metadata.PropertyName; var value = metadata.Model; //Html Construction var header = new TagBuilder("h1") {InnerHtml = propertyName}; var paragraph = new TagBuilder("p") {InnerHtml = value.ToString()}; return new MvcHtmlString(header.ToString() + paragraph); } 

Of course, at the first look we can see no problem. But, this is just two tag. Imagine nested Html elements with Html attributes. Imagine having a lot of classes, inputs, and styles. This can become a huge method of several dozen of lines. Of course, the Html rendering is also not simple but it is always more readable than having a huge amount of classes that call each of them. This is why the next approach is very interesting.

Creating inline razor helper can be done directly into any .cshtml file but it does not have the ability to be reusable which is not something interesting. This is why, it is possible to store them into that App_Code. To create an app code, you have to right click the project and add an existing asp.net folder.

From there, you can add your .cshtml that can have several Razor helper. The use it simple. You have to use the @ following by the file name inside the App_Code following by the name of the helper.

 <div> @RazorInlineHelper.MyFirstRazorHelper() </div> 

The file looks like this:

 @helper MyFirstRazorHelper() { <p>Test Razor</p> } 

We can have parameter link Html Helper. If we try to reproduce previous method from the Html helper into Razor Helper the file would look like this.

 @helper MyFirstRazorHelper() { <p>Test Razor</p> }

@helper YourGenericHelperFor(string propertyName, string value) {

<h1>@propertyName</h1><p>@value</p> }

@helper YourGenericHelperPropertyConstructedFor(string propertyName, string value) {

<h1>@propertyName</h1><p>@value</p> } 

We can see that it is not possible to use Lambda expression to get attribute value or to get value. You have to pass them as parameter. For example, the YourGenericHelperFor was changed to get two strings. One for the property name and one for the value. The use looks like this:

 <div> @RazorInlineHelper.MyFirstRazorHelper() </div> <div> @Html.TextBoxFor(d => d.Name) </div> <div> @RazorInlineHelper.YourGenericHelperFor(@Html.DisplayNameFor(d=>d.Name).ToString(), @Model.Name) </div> <div> @RazorInlineHelper.YourGenericHelperPropertyConstructedFor(@Html.DisplayNameFor(d => d.Name).ToString(), @Model.Name) </div> 

One other limitation is the use of existing Html helper. StackOverFlow has a solution to create an Html Helper that do some trick to access the Html helper of the page. Here is one solution.

 public static HtmlHelper<object> GetPageHelper(this System.Web.WebPages.Html.HtmlHelper html) { return ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Html; } 

It is possible from there to use inside your Helper @Html.

I added the whole post code into GitHub for you to play around with the code. Have fun using Html helper and Razor Helper. Keep in mind that Helper does not do as much as Html Helper but can in the hand be a lot more easier to maintain.