ASP.NET MVC 3 and the @helper syntax within Razor

ASP.NET MVC 3 supports a new view-engine option called “Razor” (in addition to continuing to support/enhance the existing .aspx view engine).  Razor minimizes the number of characters and keystrokes required when writing a view template, and enables a fast, fluid coding workflow.

Unlike most template syntaxes, with Razor you do not need to interrupt your coding to explicitly denote the start and end of server blocks within your HTML. The Razor parser is smart enough to infer this from your code. This enables a compact and expressive syntax which is clean, fast and fun to type.

You can learn more about Razor from some of the blog posts I’ve done about it over the last last 9 months:

Today’s blog post covers a cool feature of Razor that a lot of people don’t know about – which is the ability to define re-usable helper methods using the @helper syntax.

Simple @helper method scenario

The @helper syntax within Razor enables you to easily create re-usable helper methods that can encapsulate output functionality within your view templates.  They enable better code reuse, and can also facilitate more readable code.  Let’s look at a super-simple scenario of how the @helper syntax can be used. 

Code before we define a @helper method

Let’s look at a simple product listing scenario where we list product details, and output either the price of the product – or the word “FREE!” if the item doesn’t cost anything:

image

The above code is fairly straight-forward, and Razor’s syntax makes it easy to integrate server-side C# code within the HTML. 

One place that is a little messy, though, is the if/else logic for the price.  We will likely output prices elsewhere within the site (or within the same page), and duplicating the above logic everywhere would be error-prone and hard to maintain.  Scenarios like this are prime candidates to extract and refactor into helper methods using the @helper syntax.

Refactoring the above sample using the @helper syntax

Let’s extract the price output logic, and encapsulate it within a helper method that we’ll name “DisplayPrice”.  We can do this by re-writing the sample to the code below:

image

We’ve used the @helper syntax above to define a reusable helper method named “DisplayPrice”.  Just like a standard C#/VB method, it can contain any number of arguments (you can also define the arguments to be either nullable or optional).  Unlike standard C#/VB methods, though, @helper methods can contain both content and code, and support the full Razor syntax within them – which makes it really easy to define and encapsulate rendering/formatting helper methods:

SNAGHTML20fae4df

You can invoke @helper methods just like you would a standard C# or VB method:

SNAGHTML20fcdc86

Visual Studio will provide code intellisense when invoking the method:

image

Reusing @helpers across multiple views

In the example above, we defined our @helper method within the same view template as the code that called it.  Alternatively, we can define the @helper method outside of our view template, and enable it to be re-used across all of the view templates in our project.

We can accomplish this by saving our @helper methods within .cshtml/.vbhtml files that are placed within a \App_Code directory that you create at the root of a project.  For example, below I created a “ScottGu.cshtml” file within the \App_Code folder, and defined two separate helper methods within the file (you can have any number of helper methods within each file):

SNAGHTML2107b6ae

Once our helpers are defined at the app level, we can use them within any view template of our application. 

The ScottGu.cshtml template in the \App_Code folder above will logically compile down to a class called “ScottGu” with static members of “DisplayPrice” and “AnotherHelper” within it.  We can re-write our previous sample to call it using the code below:

SNAGHTML210d65c1

Visual Studio will provide code intellisense when calling app-level helpers like this:

image

May 15th Update: One issue that a few people have pointed out is that when a @helper is saved within the \app_code directory, you don’t by default get access to the ASP.NET MVC Html helper methods within it (e.g. Html.ActionLink(), Html.TextBox(), etc).  You do get access to the built-in HTML helper methods when they are defined in the same file as your views.  This is not supported out of the box, though, when the helpers are within the \app_code directory - we’ll add this in the next release.  Paul Stovall has a nice helper class that you can use in the meantime to access and use the built-in Html helper methods within @helper methods you define in the \app_code directory.  You can learn how to use it here.

Summary

Razor’s @helper syntax provides a convenient way to encapsulate rendering functionality into helper methods that you can re-use within individual view templates, or across all view templates within a project. 

You can use this functionality to write code that is even cleaner and more maintainable. 

Hope this helps,

Scott

P.S. In addition to blogging, I am also now using Twitter for quick updates and to share links. Follow me at: twitter.com/scottgu

63 Comments

  • Very nice new help syntax. I love it, thanks Scottgu

  • Nice! This will indeed be handy; didn't know it was coming. How about a nice helper that transfers Razor (C#) value references to jQuery variables/prototypes? Something like @jQVar? Just reaching a little...

  • I loved how you went from this:

    public static class Helpers
    {
    public static MvsString MyField(this HtmlHelper helper, object value)
    {
    //(...)
    }
    }

    to this:

    @helper MyField(object value){
    //(...)
    }

    Much cleaner syntax and intuitive usage.

    Congrats and thank you!

  • There's always that bit of repetitive html/code that you're unsure if it should be an extension on HtmlHelper, or a PartialView. I think this fits beautifully in between those two for those kind of scenarios. Nice work.

  • Thanks for the post! But i've got one question. Why do you back to the old App_Code instead of something like \Views\Helpers path? I think that using the path like \Views\Helpers should be more logic and pretty.

  • Scott please blog when you will retire! You obviously forgot how to write code like the rest of folks at Microsoft. Serious it is time for you to go. hopefully soon the tablet and phone market will take off and Microsoft will be a distant memory like IBM. I can't wait.

  • I got to admit, I didn't know about it. Nice post. This is kind of an alternative to partial views, so when to use Partial Views and when to use @helper? My guess is it's best to use Partial Views for stuffs that are shared across different views.

    Internally what happens ? Does it create a static method? If so, how about the changes to it, do we need to "recompile" the app or it works just like partial views where we just change the syntax?

  • Brilliant! ... Just brilliant!

  • Cool Stuff! Nice addition!! MVC Rocks!!!

  • I didn't know about this until reading this article - Razor is indeed awesome.

  • Fantasic, that's very clear Scott! I'm finally 'getting it' thanks to your nice posts.
    Cheers!

  • Very nice feature ! good job

    How to write output cache directive with razor syntax on views like aspx or ascx ?

  • Nice extension to the Razor syntax. Am I understanding correctly (seeing the intellisense) that these little helper methods can also be tested by a unit-test?

  • I'm a bit confused by the App_Code folder in WebApplication project though. Would this still work if compiling views is turned on in the project settings?

  • Great post, Scott, thanks! But, do you know, how fast is this solution, performancewise?
    Is this method faster or slower when compared to regular HtmlHelper or Html.RenderAction methods?

    Thanks in advance!

  • Hi Scott,

    What's the best way to reuse the helpers across multiple applications?

  • Great feature for simple helpers, but App_Code really? That's a bit webformish what's wrong with views/shared/helpers?

  • Very nice! @helper method is awesome!

  • hmmm is this the way to go ??
    shall we put the code snippets of helpers in a code behind aka *.cshtml.cs
    and maybe then we can put that code in a controler so that we have an MVC inject in MVC :D

    no seriously, as long a developers only see this a hack in RAD projects it's fine. coz i get a little bit of classic asp flash back (old wine new bottles)

  • Thanks for posting this - looks like a nice feature.

    The App_Code folder seems like a silly location though - should be in the Views/Shared folder somewhere.

  • Where is the difference between App_Code and Shared under View folder?

  • Is an "App_Code" folder really the best location for these kind of files. I guess its only semantics but shouldn't View Helpers be kept in the Views folder?

  • ¡Excelent post!

    Best regards from Argentina.

  • Excellent code shortcut. Neat and powerfull

  • Scott, How would you handle this with a site with many many Areas? I seem to remember trying this awhile back and having alot of trouble getting it to work. Thanks.

  • Is it possible to use the helper across application domains?
    I'd like to create a central helper repository that can be used by more than one ASP.NET MVC applications.

  • @helpers always need the @ symbol, even when inside code blocks, right?

  • Scott. First of all, thanks for the post!

    Now, I just upgraded a few of my old
    public static MvcHtmlString MyHelper(this HtmlHelper helper...

    to the new
    @helper MyHelper(....

    Looks great! Works great! The only things that I'm missing are the summaries for these functions.
    My old helpers had summaries
    /// Html Helper for such and such bla..
    /// The bla bla param

    /// Param2, more bla...

    so that when developers are working with them, they get intellisense.

    Is there any way to put summaries into @helpers? If not, I would like to suggest implementing this functionality in the future. Thank you!

  • This looks like something that can easily become a pain if used more than sparingly. First I'll end up with a bloated cshtml file full of unrelated helper methods. Then I'll try to make separate cshtml files to organize my helper methods based on domain models. Then other developers will start duplicating business logic in there....Shouldn't something like this be in the View Model?

  • Really Very good and useful feature!!!

    Thanks

  • Nice feature, thanks for the good job you've done!

  • It looks like helpers can't be called recursively?

    @helper ListCategories(Category parent)
    {
    // Do some stuff

    foreach (Category item in Model.Where(c => c.ParentId == parentId))
    {

    // Write some html

    ListCategories(item);
    }
    }

    In the above example, only the initial call to ListCategories executes, the recursive calls seem to be completely ignored.

  • Disregard the above, I found that even though the intellisense lists the method inline in the helper without the @ prefix, it still needs to have this otherwise it doesn't execute. After adding the @ before the call, the recursion works fine.

    Good job, saves having to write HtmlHelpers for no real reason :)

  • @Jarod,

    >>>>>> How about a nice helper that transfers Razor (C#) value references to jQuery variables/prototypes? Something like @jQVar? Just reaching a little...

    Good suggestion. We don't have something like that today - but we are always looking to add things in the future.

    Thanks,

    Scott

  • @Alexander,

    >>>>>> Thanks for the post! But i've got one question. Why do you back to the old App_Code instead of something like \Views\Helpers path? I think that using the path like \Views\Helpers should be more logic and pretty.

    It would have ideally been in a directory like that - but implementing that unfortunately would have taken a bit longer than we had. The \App_Code approach works because of some existing infrastructure we already had in ASP.NET - and so we ended up going with that for the first release of Razor. I'm hoping we'll be able to support more path locations in the future.

    Hope this helps,

    Scott

  • @Parag,

    >>>>>>> Internally what happens ? Does it create a static method? If so, how about the changes to it, do we need to "recompile" the app or it works just like partial views where we just change the syntax?

    Internally it compiles to a class with static methods. ASP.NET automatically detect changes and will use them with the next request to the app. So no need to explicitly recompile - this works just like with partial views.

    Hope this helps,

    Scott

  • @Paul,

    >>>>>>> On MVC projects I had trouble making App_Code @helpers work with the MVC Html.ActionLink (etc.) helpers - my solution is linked below, but is there a better way?

    Unfortunately that is a limitation in ASP.NET MVC 3 with the @helpers. I will update the blog post to call that out. We'll support the full MVC context in helpers with the next release. The workaround you are using right now will help mitigate it.

    Hope this helps,

    Scott

  • @Chouteau

    >>>>>>> How to write output cache directive with razor syntax on views like aspx or ascx ?

    I'd recommend using the Html.Action() helper method to achieve this. I plan to do a blog post about this technique soon.

    Hope this helps,

    Scott

  • @ElmarG,

    >>>>>>> Nice extension to the Razor syntax. Am I understanding correctly (seeing the intellisense) that these little helper methods can also be tested by a unit-test?

    There isn't any direct support for unit testing these at the moment. However, if you unit test your views you they can participate.

    Hope this helps,

    Scott

  • @Mike,

    >>>>>>>> I'm a bit confused by the App_Code folder in WebApplication project though. Would this still work if compiling views is turned on in the project settings?

    Conceptually you can think of the project compiling first - with all of the non-view code in the project being compiled into an assembly in the \bin directory. ASP.NET at runtime then compiles the \App_Code folder and references all of the assemblies in the \bin folder. View templates under the \Views folder are then compiled on demand and will reference both the \bin and \App_Code output.

    Hope this helps,

    Scott

  • @fran,

    >>>>>>>> Great post, Scott, thanks! But, do you know, how fast is this solution, performancewise? Is this method faster or slower when compared to regular HtmlHelper or Html.RenderAction methods?

    This approach should be the same performance-wise as writing a custom HtmlHelper. Both compile down to a class - and so the compiled code is equivalent at runtime.

    Hope this helps,

    Scott

  • @jarimba,

    >>>>>> What's the best way to reuse the helpers across multiple applications?

    Check out this cool tool to do that: http://razorgenerator.codeplex.com/

    Hope this helps,

    Scott

  • @DalSoft,

    >>>>> Great feature for simple helpers, but App_Code really? That's a bit webformish what's wrong with views/shared/helpers?

    It would have ideally been in a directory like that - but implementing that unfortunately would have taken a bit longer than we had. The \App_Code approach works because of some existing infrastructure we already had in ASP.NET - and so we ended up going with that for the first release of Razor. I'm hoping we'll be able to support more path locations in the future.

    Hope this helps,

    Scott

  • @Matt,

    >>>>>> Thanks for posting this - looks like a nice feature. The App_Code folder seems like a silly location though - should be in the Views/Shared folder somewhere.

    It would have ideally been in a directory like that - but implementing that unfortunately would have taken a bit longer than we had. The \App_Code approach works because of some existing infrastructure we already had in ASP.NET - and so we ended up going with that for the first release of Razor. I'm hoping we'll be able to support more path locations in the future.

    Hope this helps,

    Scott

  • @smnbss,

    >>>>>>> Have these problem being fixed in the release version?

    Unfortunately that is a limitation in ASP.NET MVC 3 with the @helpers - it does not have built-in context of the MVC helpers. I will update the blog post to call that out. We'll support the full MVC context in helpers with the next release. There is a helper workaround in that first StackOverflow post, though, that describes how to still get access to the MVC Context.

    Hope this helps,

    Scott

  • @stephen,

    >>>>>>> Is an "App_Code" folder really the best location for these kind of files. I guess its only semantics but shouldn't View Helpers be kept in the Views folder?

    It would have ideally been in a directory like \Views\Helpers - but implementing that unfortunately would have taken a bit longer than we had for the release. The \App_Code approach works because of some existing infrastructure we already had in ASP.NET - and so we ended up going with that for the first release of Razor. I'm hoping we'll be able to support more path locations in the future.

    Hope this helps,

    Scott

  • @tps,

    >>>>>>> Scott, How would you handle this with a site with many many Areas? I seem to remember trying this awhile back and having alot of trouble getting it to work. Thanks.

    I believe this will work from areas as long as the areas are in the same project.

    Hope this helps,

    Scott

  • @herry,

    >>>>>>>> Is it possible to use the helper across application domains? I'd like to create a central helper repository that can be used by more than one ASP.NET MVC applications.

    This blog post describes how you could create a class library project of re-usable helpers: http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries.aspx

    Hope this helps,

    Scott

  • @Dimskiy,

    >>>>> Is there any way to put summaries into @helpers? If not, I would like to suggest implementing this functionality in the future. Thank you!

    That is a good suggestion! Unfortunately I don't know of a way to do this with the current release. But it is a great suggestion for the future.

    Hope this helps,

    Scott

  • @LazyProgrammer,

    >>>>>> Shouldn't something like this be in the View Model?

    Not really. Your view model classes should only contain the model information your view templates require - and shouldn't have any HTML generation logic within them. The @helper methods above are really about HTML generation, and you can optionally pass them ViewModel data to work with.

    Hope this helps,

    Scott

  • Thanks for the article, this works great and lets me get rid of my custom FormatHelper class. The one thing that didn't work was adding a model reference at the top of the helper file, however referencing the function with the full namespace did work. For example:

    @helper EncodeURL(string text)
    {
    @Housters.Business.Utility.Helpers.URLHelper.Encode(text)
    }

  • Very helpful as always. Thanks Scott!

  • There's something really smelly about Razor. Consider this:

    @Html.ActionLink("Home", "Index", "Home")
    @Html.ActionLink("About", "About", "Home")


    The closing tag is not required by the html standard. I should be able to leave it out if that is my choice. But if I do, the razor syntax will fail. I just think that stinks.

  • Hi Scott,
    is something similar planned for CSS? I.e. do you have something like 'LESS for ASP.net' in the pipeline?
    Cheers, Lukas

  • This is great. Thanks for such helpful guide.

  • Scott, thanks for the article. We tried the helpers but came to issues where generic helpers would help us.

    Will Razor support generic helpers?

  • @LazyProgrammer said:
    >> "Shouldn't something like this be in the View Model?"

    @Scott replied:
    >> "Not really. Your view model classes should only contain the model information your view templates require - and shouldn't have any HTML generation logic within them. The @helper methods above are really about HTML generation, and you can optionally pass them ViewModel data to work with."

    I agree your model classes shouldn't contain HTML, but surely a flattened view model that exposes a string for DisplayPrice would be a better way of achieving this particular case? That way no logic is in the view at all, no need for masses of helpers and you can test your controller and get back the view model in unit tests?

  • Hi,

    I think the logical place to put this code should be in the Model...
    Why put it in the View?... i thought MVC was about abstraction......
    Please explain....

  • every one can post their owe information,why I can not???How can I post?Thanks!!!
    You know,Christian Louboutin Shoes is very fashion,you can not miss it.In this Christian Louboutin Sales season, you deserve to have a pair of beautiful shoes with Christian Louboutin. http://www.heelsvogue.com . kindly visite our website,thanks!!!

  • Wow, this is incredibly @helpful (sorry, I couldn't resist myself). Thanks for bringing this to my attention, Scott!

  • I like your post, hope you will share more with us,thanks!

  • How can you use the various Html.XxxFor() methods within a helper? They take a generic argument (Expression<Func> expression), and it doesn't seem possible to specify a generic argument into a helper method. Is that just a huge oversight on Microsoft's part, or was there some underlying conceptual reason that generic helpers aren't supported?

  • Love the @helper syntax. Thanks for this awesome post.

Comments have been disabled for this content.