Text templating using Razor the easy way

code, asp.net, razor 0 comments suggest edit

As a web guy, I’ve slung more than my fair share of angle brackets over the tubes of the Internet. The Razor syntax quickly became my favorite way of generating those angle brackets soon after its release. But its usefulness is not limited to just the web.

The ASP.NET team designed Razor to generate HTML markup without being tightly coupled to ASP.NET. This opens up the possibility to use Razor in many other contexts other than just a web application.

For example, the help documentation for NuGet.exe is written using the Markdown format that is produced by NuGet.exe. NuGet.exe reflects over its own commands and uses a Razor template to generate the properly formatted output.

The check-in that enabled this caught my eye and prompted me to write this blog post as it’s a very clean approach. I’ll show you how to do the same thing in no time at all.

RazorGenerator

The first step is to install the RazorGenerator extension from the Visual Studio Extension Gallery.

If you haven’t used the Extension Gallery before, within Visual Studio click on the Tools > Extension Manager menu option to launch the Extension Manager dialog. Select the Online tab and type in “RazorGenerator” (without the quotes) in the upper right search bar.

Make sure to install the one named “Razor Generator” (not to be confused with “Razor Single File Generator for MVC”).

razorgenerator-in-vs-extension-gallery

Create your application

For my sample application, I created a simple console application and added a reference to the following assemblies:

  • System.Web.WebPages.dll
  • System.Web.Helpers.dll
  • System.Web.Razor.dll

I then added a new text file and named it RazorTemplate.cshtml. You can name yours whatever you want of course.

Make sure to set the Custom Tool for the CSHTML file to be “RazorGenerator”. To do that, simply right click on the file and select the Properties menu option. Type in “RazorGenerator” (sans quotes) in the field labeled Custom Tool.

Razor-file-properties

I added the following code within the CSHTML file:


@* Generator : Template TypeVisibility : Internal *@
@functions {
  public dynamic Model { get; set; }
}
<ul>
@foreach (var item in Model) {
  <li>@item.Name (@item.Id)</li>  
}
</ul>

That first line is a generator declaration. It’s required to by the Razor Generator. I chose to make the generated template class internal.

The next line starts a functions block. I specify a property for the template named Model in there. If you’re not a fan of the dynamic keyword, please don’t freak out. At least not yet.

I simply chose a dynamic property for the purposes of demonstration, but I could have just as easily made it a strongly typed property. Well, not just as easily as I would have had to create a another type first. But you get the idea.

In fact, I could have added multiple properties to this template if so desired. These properties and methods added here will show up in the generated template class.

The next section is simply the usual razor syntax markup you know and love which is written against the property I defined. In case you’re out of practices with Razor, be sure to check out the C# Razor Syntax Quick Reference I wrote a while back.

Render the template

Now all we need to do is instantiate the template, populate the properties we defined in the template with real values, and we’re done!

So what exactly are we instantiating? The steps we took up until now results in the Razor file generating a template class. If you expand the CSHTML file, you can see the generated class.

Razor-Generated

That’s the class we need to instantiate. Here’s some code I added in Program.cs that makes use of this generated template class.

class Program {
    static void Main(string[] args) {
        var template = new RazorTemplate {
            Model = new[] { 
                new {Name = "Scott", Id = 1},
                new {Name = "Steve", Id = 2},
                new {Name = "Phil", Id = 3},
                new {Name = "David", Id = 4}
            }
        };
        Console.WriteLine(template.TransformText());
        Console.ReadLine();
    }
}

The code is very straightforward. It simply instantiates an instance of the RazorTemplate class and sets the Model property (which is the property I defined within the template) as an array of anonymous objects.

Again, for demonstration purposes, I’m using a dynamic property to access anonymous objects. You can just as well pass in and render strongly typed properties.

After instantiating the template instance, we simply call the TransformText method on it and write the response to the console.

razor-output

Easy as stepping on a Lego block in the dark!

Note that using Razor as a general text templating langage might not always produce the best results. It was heavily geared towards rendering markup (aka angle brackets) which it’s very good at. Your mileage may vary when attempting to render other types of textual output.

In a following post, I’ll show you a cool way I’m using this technique for a library I’ve been working on meant to demonstrate some cool internals of ASP.NET MVC.

Some of what I’ve shown here has been shown before in the context of ASP.NET MVC. Those other posts are worth reading as well. For example…

I hope you find this useful for your text templating needs!

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

30 responses

  1. Avatar for Tomas
    Tomas August 1st, 2011

    Nice post. How do you combine this with the markdown syntax? And what is used to generate the documentation page from the markdown markup?

  2. Avatar for gOran
    gOran August 1st, 2011

    Nice one, i just can't wait next post about this.
    Thanks for sharing!

  3. Avatar for pete w
    pete w August 1st, 2011

    Very handy, but I think you should add a caveat: for those of us building software in SharePoint, this will not currently work (as of 8/1/2011) because SharePoint runs on .NET3.5 and Razor requires the dynamic features of .NET 4.0
    I once evaluated using Razor in a SharePoint solution and ended up using Castle NVelocity with works just as well for my needs

  4. Avatar for Ignat Andrei
    Ignat Andrei August 1st, 2011

    Sorry for being unhandy - but I search
    RazorGenerator
    in Extension Manager and did not found.( neither with
    Razor
    , neither with
    generator
    )
    Does it matter that I use VSWD Express?

  5. Avatar for AlexandreJobin
    AlexandreJobin August 1st, 2011

    What is the difference between RazorGenerator & RazorEngine that we can find here: http://razorengine.codeplex.com ?
    are they doing the same thing but differently? Can i do an Email template and i render on the fly with RazorGenerator?
    alex

  6. Avatar for Marcus Swope
    Marcus Swope August 1st, 2011

    I'm guessing this is how we are going to be writing HTML5 apps that run on Windows 8?

  7. Avatar for Quentin
    Quentin August 1st, 2011

    Is it possible to use a separate layout file when generating templates this way? That always seemed to pose a hurdle with previous razor generating techniques, like the aforementioned codeplex project.

  8. Avatar for sab
    sab August 2nd, 2011

    I could not find the package
    nuget.org/.../Search

  9. Avatar for Buildstarted
    Buildstarted August 2nd, 2011

    Alexandre, the difference is that this is a precompiled method while the RazorEngine compiles on the fly. The RazorEngine allows you to pull views from alternate locations that can be modified if necessary. This particular method just compiles them ahead of time.

  10. Avatar for Buildstarted
    Buildstarted August 2nd, 2011

    Ignat, visualstudiogallery.msdn.microsoft.com
    Sab, you're looking for "PrecompiledMvcViewEngine" instead. nuget.org/List/Packages/PrecompiledMvcViewEngine

  11. Avatar for David Ebbo
    David Ebbo August 2nd, 2011

    @tomas: see the code in http://nugetdocs.codeplex.com/ for details on how the nuget doc site works.

  12. Avatar for David Ebbo
    David Ebbo August 2nd, 2011

    @pete_w: the 4.0 requirement is a general Razor engine thing, and not specific to RazorGenerator.
    @Ignat: VS express indeed does not support most extensions, so it won't work there.

  13. Avatar for David Ebbo
    David Ebbo August 2nd, 2011

    @Alexandre: I haven't used RazorEngine, but from what I can see, it's quite different, in the sense that it is a runtime library while RazorGenerator is a design time tool. With RazorGenerator, code gets generated and compiled as part of your project, such that at runtime there is no dependency on Razor, and no on-the-fly compilation. See my posts on RazorGenerator (http://blog.davidebbo.com/search/label/Razor) to see examples of what it's good for.

  14. Avatar for David Ebbo
    David Ebbo August 2nd, 2011

    @Quentin: could you start a discussion on http://razorgenerator.codeplex.com/ with more details about the layout scenario you have in mind? It's possible that we can do something there, but we need to make sure we're talking about the same thing :)

  15. Avatar for krislig
    krislig August 3rd, 2011

    I know that this is crazy but:
    Can you use Razor Engine to generate XAML markup to produce this ugly XML like file in WPF projects?

  16. Avatar for Micah Smith
    Micah Smith August 3rd, 2011

    Thank you for writing this--today i was searching for different template languages to use against xml. I often get "can you use XSLT 2.0" questions about a .NET product we use, and since 1) microsoft hasn't moved to XSLT 2.0 and 2) why would they? Newer template languages like razor/jade/haml have ushered in an era of a much more syntactically friendly form and well... As soon as i hit this "leave your mark" button below this form i'm going to search "xml to dynamic .NET" on google. Thanks phil

  17. Avatar for Josh Carroll
    Josh Carroll August 4th, 2011

    So what about T4?
    I know this isn't a fair analogy, but it reminds me of the Linq2Sql vs Entity Framework issue.
    We now have two competing technologies within the MS stack that overlap a bit. Razor has a nicer syntax, is lighter weight, and more specialized. Whereas T4 is more general purpose, but the learning curb is a bit steeper...
    Personally... I think it would be awesome if T4 adopted a more razor like syntax. Are the two sides talking, or is this just wishful thinking on my part :)

  18. Avatar for haacked
    haacked August 4th, 2011

    @Josh I think it's pretty extreme to compare this to the Linq2Sql and EF comparisons.
    T4 is primarily a general purpose text transformation language. Razor is optimized for HTML generation. If you try and generate C# code with Razor, you'll find it's a bit painful. That's not it's sweet spot nor its design intention.

  19. Avatar for Mikhail Petrovskikh
    Mikhail Petrovskikh August 11th, 2011

    I tried to add an in-page razor helper in my template with "@helper HelperName(){}" syntax. It looks like the code generated by the Razor Generator is missing some references to System.Web.WebPageExecutingBase for static methods WriteTo and WriteLiteralTo. When I added @using System.Web in the template and prepended these functions with the class name "WebPageExecutingBase." everything worked fine but it gets overwritten if you change the template(obviously).

  20. Avatar for Jadall
    Jadall August 29th, 2011

    Josh, you must be high out of your mind

  21. Avatar for simon weaver
    simon weaver September 19th, 2011

    @haacked can you add a note explaining where to find
    System.Web.WebPages.dll
    System.Web.Helpers.dll
    System.Web.Razor.dll
    I had a WPF project that i had to change from .NET Framework 4 Client Profile > .NET Framework 4 to be able to see these DLLS under 'Add Reference'. I think that's the correct way right?

  22. Avatar for simon weaver
    simon weaver September 19th, 2011

    In addition to the extension, the latest version of the Razor Generator requries the Nuget package RazorGenerator.Templating for the RazorGenerator.Templating.RazorTemplateBase base class
    razorgenerator.codeplex.com/discussions/271171

  23. Avatar for ctrlShiftBryan
    ctrlShiftBryan October 20th, 2011

    Thanks Simon for the hint at needing to
    PM> Install-Package RazorGenerator.Templating

  24. Avatar for Ben Wilde
    Ben Wilde June 17th, 2013

    This is only *slightly* important... ;)

  25. Avatar for Aaron Shumaker
    Aaron Shumaker January 31st, 2014

    Phil, major typo in code example, a stray span tag, really confused me? `dynamic</span> Model`

  26. Avatar for haacked
    haacked January 31st, 2014

    Thanks! I fixed it and it should show up shortly.

  27. Avatar for John
    John June 11th, 2014

    I am attempting to use this method for creating plugin templates. I would like to be able to gain access to the @Html.Helper helper library. I have attempted to pass the helper itself as a parameter to the model but the generated cs class complains about no access to the helper methods. Any thoughts?

  28. Avatar for dvc1201
    dvc1201 April 14th, 2015

    Brilliant idea. Could you help me please how can I get the rendered HTML as a string from a
    System.Web.WebPages.WebPage object.
    I've modified
    @* Template : Template TypeVisibility : Public *@ to
    @* Generator : WebPage TypeVisibility : Public *@
    (because I would like to use @RenderPage as well)
    so is there a method or process for a WebPage which shows the same effect as template.TransformText()); in the original example?
    Thanks

  29. Avatar for Paul d'Aoust
    Paul d'Aoust April 20th, 2015

    "Easy as stepping on a Lego block in the dark."

    Spoken like a father.

  30. Avatar for Jeffrey Reddy
    Jeffrey Reddy February 6th, 2018

    Couldn't get this to work with Visual Studio 2017 and the latest version of .NET. Any chance this could be updated? Thanks,