This post is over 6 months old. Some details, especially technical, may have changed.

The Razor View Engine

Sorry for the poor syntax highlighting on the source code... not much support for Razor ATM

I've been holding off trying to form an opinion on this until we got the full package so to speak.  With MVC 3 RC1 being released last week I guess it's time to share my thoughts on the mildly contentious view engine.  First things first though - lets be extremely superficial and compare a a bit of code.  Specifically lets look a using a loop to output a list of "really useful" list items.  In the older WebForms view engine you'd do something like this.

<ul>
    <% foreach (int index in Enumerable.Range(1, 10))
        { %>
        <li>Entry <%=index%></li>
    <%}%>
</ul>

Even for a very trivial example it does look a bit messy - lots of redundant start and end markers etc.  Lets look at the equivalent in Razor,

<ul>
    @foreach (int index in Enumerable.Range(1, 10))
    {
        <li>Entry @index</li>
    }
</ul>

Now excuse me while I go off on a tiny bit of a tangent.  There are two things you probably notice about the equivalent Razor syntax,

  1. It's much cleaner because of some very clever parsing
  2. It's still embedding code in a view.  THE HORROR!!!!

Yeah I know in this day and age when everyone is trying to eradicate every suggestion of server code in a view Microsoft have went right ahead and actually enabled you to do it in neat/cleaner manner.  It works though - doesn't it?  I mean why abstract C# when your view is going to get compiled into C#?  Why try and mimic HTML/XML when technically speaking your custom markup is pretty much meaningless?  What's wrong with being able to see when server side syntax finishes and front end syntax takes over?  It makes a lot of sense to me actually.

The Truth Will Out

I've been holding off judgement on Razor for a while until it was more "complete".  Truth be told for a long time I could have easily summed it up as

It's the WebForms View Engine with the <% %> replaced with @

In some ways thats true but at an extremely basic level.  I misjudged it.  I was wrong.  I actually kind of like it now.

But what about Spark?

I've been an advocate of the Spark View Engine for sometime in my company and I've used it on a few projects very successfully.  It's a great engine but has suffered from a lack of tooling - there are plenty of developers that simply reject or get a negative impression of something because of the lack of tooling for the tech.  Spark, especially in comparison to Razor, has very limited tooling support in VS2010 - sure you have SparkSense but it's currently not a patch on Razor support (which is still in itself RC status) and I can't help but feel they'll always be playing catch-up with in house developed/supported stuff.  Would I have like to see Spark being adopted by MS rather than them rolling their own view engine?  Perhaps, but variety is the spice of life and I'm happy to have Razor around.

So what will I use on future projects?  I'm tending towards Razor for now but perhaps that's because it's new and I'm a technology magpie.  Also it easier to justify the use of a technology to a customer when they are provided pre-bundled and supported by such a large entity.

</opinion piece>

Back On Track

Now I've had my little digression lets look at some of the features of Razor.

Syntax

As I showed above the syntax is much more terse.  The parser is clever enough to detect when you mean server code and when you mean client code.  This reduces the need to use a lot of bulky delimiters like <% and %>.  Also the parser is able to determine if the @ you just wrote is a server side delimiter or just plain text - most of the time.  Alternatively you can fall back on the @@ syntax to use a literal @. 

The parser does choke sometimes when you don't wrap text in an appropriate element or tag

@if (true)
{
    this is a test
}

fails whereas

@if (true)
{
    <span>this is a test</span>
}

is fine.  If you really insist on not using an HTML element you can fall back on one of two things.  Using a <text> element that is a Razor tag for marking an area for processing as plain text or a slightly shorter single line equivalent of @:

@if (true)
{
    <text>this is a test</text>
}

@if (true)
{
    @:this is a test
}

Layouts and Sections

Razor (obviously) has support for master pages and rending content sections including optional sections.  Syntax for it is pretty simple, lets start with our master page _Layout.cshtml

<!DOCTYPE html>
<html>
    <head>
        <title>@View.Title</title>
    </head>
    <body>
        <div id="menu">
            @RenderSection("menu", required: true);
        </div>
        <div id="content">
            @RenderBody()
        </div>
        <div id="footer">
            @RenderSection("footer", required: false);
        </div>
    </body>
</html>

Couple of features worth mentioning,

  1. Use of RenderSection() to render named sections from the view, also able to specify if the section is a required or optional section throught the use of the required argument (i.e. if it needs to or doesn't need to be included in the view during render - if required is true and the section is missing you'll get a runtime error when you attempt to access the page).  Another option for optional sections is to use the IsSectionDefined method e.g.

    <div id="footer">
        @if (IsSectionDefined("footer"))
        {
            RenderSection("footer");
        }
        else
        {
            @:Default Footer Text
         }
    </div>
    

    This way we can, as demonstrated, provide some sort of default as well.

  2. RenderBody convenience method.  This is used to render the body of the view.  Unlike WebForms view engine Razor doesn't require you to wrap the main body in a content area - similar to Spark. 

So an appropriate view that this master layout can "consume" could look like this

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h1>Super Useful Page</h1>
<p>It really is super useful</p>

@section menu {
<ul>
    <li>Login</li>
    <li>Register</li>
</ul>
}

Notice I have left out the footer but that's not an issue as it has been marked as optional.  Also notice that the body is at the root level of the view and sections are wrapped in a section marker.  This all adds a more minimal look and feel to the whole view.

_ViewStart.cshtml

Another leaf from the Spark world (and probably many other - sorry to everyone else that supports/implements this sort of feature) is the ability to provide a global place to put code that applies to every view.  Using the _ViewStart.cshtml file we could easily just put the Layout declaration from the view code above into a single global location.  We can also add helpers and functions there too which I'll talk about now.

Helpers

Helpers enable use to provide context aware reusable HTML "templates" in our views.  Imagine a view that listed Top Selling, New and Top Rated products in 3 lists.  The most basic way to implement this would be 3 loops like so

<h1>Top Selling Product List</h1>
<ul>
    @foreach (string product in View.TopSellers)
    {
        <li>@product</li>
    }
</ul>
<h1>New Product List</h1>
<ul>
    @foreach (string product in View.NewProducts)
    {
        <li>@product</li>
    }
</ul>
<h1>Top Rated Product List</h1>
<ul>
    @foreach (string product in View.TopRated)
    {
        <li>@product</li>
    }
</ul>

But that's not exactly DRY is it?  Helpers can help us out here (hence the name I guess :-P).  Lets create a helper that does the repeatable stuff for us,

@helper ProductLister(List<string> products){
    <ul>
        @foreach (string product in products)
        {
            <li>@product</li>
        }
    </ul>
}

And the rest of the view...

<h1>Top Selling Product List</h1>
@ProductLister(View.TopSellers)
<h1>New Product List</h1>
@ProductLister(View.NewProducts)
<h1>Top Rated Product List</h1>
@ProductLister(View.TopRated)

Much simpler, cleaner, whateverer.  Again with the Spark similarities - these are similar to macros.

Functions

Razor also makes it easier to embed arbitrary methods on your page which I guess can be useful for formatting and things like that.  This give us the power to extend the Razor view engine and adapt it to suit our needs - powerful yes but also open to abuse as you might guess.  Here's a simple function in action,

@functions {
    string Encrypt(string value){
        char[] asArray = value.ToCharArray();
        Array.Reverse(asArray);
        return new string(asArray);
    }
}
<ul>
    <li>Username: @View.Username</li>
    <li>Password: @Encrypt(View.Password)</li>
</ul>

The function applies a highly technical string encryption technique to a string value returning the result.

Inline Templates

One more feature before I head off to watch telly or sleep or something.  Razor allows you to pass little html nuggets or templates as arguments to helpers and functions.  There is a details blog post about this over at Vibrant Code and my example is heavily inspired/plagiarised from that.  Lets see what we can do,

@functions {
    IHtmlString Times(int times, Func<int, object> template) {
        StringBuilder b = new StringBuilder();
        for(int i = 0; i < times; i++) {
            b.Append(template(i));
        }
        return new HtmlString(b.ToString());
    }
}
<ul>
    @Times(10, @<li>List Item @item</li>)
</ul>

Look at the second to last line see that little block of html preceded by the Razor marker (@)?  See how in our Times function the HTML block it is getting translated transparently as a Func<int, object> the we can call and manipulate in the helper function anyway we want?  Can you see how powerful that could be in the right place?  Me too.  Me too.

Done For Now

There is more to Razor than all this stuff including the ability to use it outside of the view context so it could simply be a templating language if needs be.  There is even more than that too but thats for another time.  Imagine though.... I started out this blog post more or less telling you I used to think Razor was simply the WebForms view engine but with @'s instead of <% %>'s and hopefully you can see why I was wrong and why I was happy to admit it.  My only gripe is that the Razor documentation could be a bit more available.  There isn't really a great deal out there ATM.  However this has been promised for the official release so I am looking forward to that.

Oh Misfits is about to start......

Published in .NET on November 18, 2010