The Difference Between @Helpers and @Functions In WebMatrix

This is another post which was inspired by a recent question in the ASP.NET forums, when someone asked what the difference is between @functions and @helpers in ASP.NET Web Pages. Here, I look at both of these contructs and explain what they are, how they are different, and how each should be used appropriately.

Both @helpers and @functions do share one thing in common - they make code reuse a possibility within Web Pages. They also share another thing in common - they look the same at first glance, which is what might cause a bit of confusion about their roles. However, they are not the same. In essence, a helper is a reusable snippet of Razor sytnax exposed as a method, and is intended for rendering HTML to the browser, whereas a function is static utility method that can be called from anywhere within your Web Pages application. The return type for a helper is always HelperResult, whereas the return type for a function is whatever you want it to be.

A typical example of a helper is to display items in an ordered list. You create a folder called App_Code in the root of your site, if you don't have one already, and add a .cshtml file to it. You can name this file anything you like - but Helpers seems to be appropriate. Within your Helpers.cshtml file, you would add the following code:

@helper OrderedList(IEnumerable<string> items){
    <ol>
        @foreach(var item in items){
            <li>@item</li>
        }
    </ol>
}

As you can see, this code includes HTML tags and Razor code, just like it would if you were rendering an ordered list within a Web Page. When the code is compiled, OrderedList becomes a static method of non-static class called Helpers - the name of the class is taken from the file name. A sample method call could look like this:

@Helpers.OrderedList(new[] { "Blue", "Red", "Green" })

When this is executed, unencoded HTML is output to the browser. You could implement the same functionality using @functions, and here is an example which does just that. Again, you need to add a .cshtml file to App_Code, and give it a name. In this case. Functions.cshtml is as good as any:

@using System.Web.Mvc;
@using System.Text;
@functions {
    
    public static HtmlString OrderedList(IEnumerable<string> items)
    {
        var sb = new StringBuilder();
        var orderedList = new TagBuilder("ol");
        foreach(var item in items){
            var listItem = new TagBuilder("li");
            listItem.SetInnerText(item);
            sb.AppendLine(listItem.ToString(TagRenderMode.Normal));
        }
        orderedList.InnerHtml = sb.ToString();
        return new HtmlString(orderedList.ToString(TagRenderMode.Normal));
    }
}

Again, OrderedList becomes a method of a non-static class named after the file (Functions), and calling it in the page is straightforward:

@Functions.OrderedList(new[] { "Blue", "Red", "Green" })

But Oh Lordy! You've had to reference System.Text to create a StringBuilder object and System.Web.Mvc to use the TagBuilder (although you could have rendered the HTML tags as strings yourself), and make sure you returned an object of type HtmlString to ensure that the whole lot doesn't get HTML encoded when it is rendered to the ouput. Functions cannot contain intermixed HTML. Now you can see the attraction of @helpers.

The appropriate use for @functions is when you want to perform an operation on a variable, rather than output some HTML. For example, you might want to validate an incoming DateTime to ensure that it is some time in the past. You wouldn't accept a form submission where someone's date of birth is some time in the future, after all? This is where @functions can be used:

@functions {    
    public static bool IsBeforeToday(string value){
      DateTime result;
      if (DateTime.TryParse(value.ToString(), out result))
      {
        if (result < DateTime.Now)
        {
          return true;
        }
      }
      return false;
    }
}

This function takes a string as an input, and tests to see if it can be converted to a DateTime successfully. If so, it tests to see if it is before the current date and time. If it passes those tests, it returns true:

@Functions.IsBeforeToday("2010/3/22") @*returns True*@
@Functions.IsBeforeToday("2012/5/6") @*returns False at the time of writing*@

Notice that the return type for both @functions examples have differed - the first is an HtmlString, whereas the second is a bool. The return type for a method compiled from @helpers will always be HelperResult.

One other thing to note - I've emphasised that the class that is compiled as a result of the @functions syntax is non-static. This means that you cannot create extensions methods using @functions.

 

Date Posted:
Last Updated:
Posted by:
Total Views to date: 70474

11 Comments

- Jesse

Thanks for the further clarification. Great post

- Q

It's clear that Helpers always return some HTML. Do Functions always have to return a vale however?

Was trying to find this out, as all examples I have seen so far (including here) it does. I wanted a reusable bit of code that logs certain events to a text file. I thought that a Function was the logical choice for that and it also includes a try catch in there. When trying to run it however I got the error "not all code paths return a value". I thus tried adding a line in both the try and the catch to return something and then it worked.

Obviously since I'm not using those values I'm returning it seems like I'm not doing something right here.
Am I incorrectly using the Function or should I be using something other than a Function?

Thanks

- Mike

@Q,

Your function definition is just a wrapper around a C# method. You can declare it with a return type of void if you don't want to return anything:

@functions{
public static void LogThis(Exception ex){
// method body
}
}

- Andrew

The Total Views to date: ... is based on each postback. Not accurate at all!

- Mike

@Andrew,

As you have established, it's 100% accurate. Every time the page is requested, I register 1 view.

Thanks for dropping by and testing that for me.

- Bret Dev

Excellent post! One concern - where can you place global @Functions code within an MVC project to get visibility across pages? Is this unsupported?

- Mike

You can put them in an App_Code folder just like Web Pages. You may need to compile first before they are available to your views.

However, the recommended option in MVC is to create normal extension methods and put them into a class file or reusable project. The MVC version of @Helper is an extension method on the HtmlHelper type.

- Bayu Angkasa

Four years after you wrote it, I still find out how lucky I am to read your posts ... Thank you Mike !!!

- Ryan Williams

You're like the ONLY authority on WebPages. I swear we are screwed if you retire!

- Fred Solbakken

Is it possible to call e.g. @Functions.IsBeforeToday("2010/3/22")
directly from a jQuery AJAX call? Something like
ajax: {url: "@Functions.IsBeforeToday("2010/3/22")"

- Mike

@Fred,

You would create a separate file that makes the call to the function. It will act like a kind of poor man's web service. It only needs one line of code in it. I'll call the file IsBeforeToday.cshtml
@{Json.Write(Functions.IsBeforeToday(Request["date"]),Response.Output);}

Then you would call if from jQuery like this:
$(function () {

$.get('/IsBeforeToday/',{date: your_date_value}, function(result){
console.log(result);
});
});

Recent Comments

Justin Kusuma 7/24/2015 3:38 AM
In response to Posting Data With jQuery AJAX In ASP.NET Razor Web Pages
Hi Mike, thanks much for sharing such an article :) Really help me a lot... further, I'd like to...

Michael Easterbrook 7/22/2015 5:35 PM
In response to Inline Razor Syntax Overview
I removed the @ symbols and I am still getting the same error. It only occurs when I have an "if" a...

Sujay 7/22/2015 1:36 PM
In response to ASP.NET MVC, Entity Framework, One-to-Many and Many-to-Many INSERTS
can you explain how to link two tables so that it forms many to many relationship?(Article and...

Max G 7/21/2015 9:29 PM
In response to Scheduled Tasks In ASP.NET With Quartz.Net
Hi, I've opted for this solution in one of my applications but i've found that the apppool is and I...

Michael Easterbrook 7/20/2015 4:31 PM
In response to Inline Razor Syntax Overview
When I have the following code: @foreach (var procRow in procRowDecade) { if (@procRow[3] +...

Shanice 7/18/2015 10:58 PM
In response to A Better Way To Export Gridviews To Excel
Hi. I'm working with mvc. I need to add the above code in the business logic layer, however the...

Matt 7/18/2015 6:29 PM
In response to Nested Layout Pages with Razor
Cheers sir, nice explanation :)...

Keshavan 7/17/2015 9:06 AM
In response to Scheduled Tasks In ASP.NET With Quartz.Net
Hi Mike, I have followed exactly as illustrated in blog, I get error "StdSchedulerFactory.cs" not...

Paul Thiel 7/16/2015 5:17 PM
In response to ASP.NET 5 By Numbers
Comments Below: "The new version of ASP.NET is called ASP.NET 5. It is a framework for developing...

saket singh 7/16/2015 8:42 AM
In response to Scheduled Tasks In ASP.NET With Quartz.Net
hi Mike, great tutorial on Quartz.net , but i have One Problem , Everything is working fine as as...