It was just after I started learning ASP.NET MVC that Scott Guthrie announced a Razor view engine for that platform. I was previously aware of the Razor syntax but had never used it, and frankly I had no problem with the older syntax.

In his initial blog post introducing Razor, ScottGu says

We think “Razor” provides a great new view-engine option that is streamlined for code-focused templating. It a coding workflow that is fast, expressive and fun. It’s syntax is compact and reduces typing.

I would rarely disagree with a developer of ScottGu's standing but on this occasion... I hate Razor.

The design goals

I’ll offer some examples, but before I do so I’ll set out the “design goals” which ScottGu and his team had in mind (which are stated on that above link).

  • Compact, Expressive, and Fluid: Razor minimizes the number of characters and keystrokes required in a file, and enables a fast, fluid coding workflow. Unlike most template syntaxes, you do not need to interrupt your coding to explicitly denote server blocks within your HTML. The parser is smart enough to infer this from your code. This enables a really compact and expressive syntax which is clean, fast and fun to type.
  • Easy to Learn: Razor is easy to learn and enables you to quickly be productive with a minimum of concepts. You use all your existing language and HTML skills.
  • Is not a new language: We consciously chose not to create a new imperative language with Razor. Instead we wanted to enable developers to use their existing C#/VB (or other) language skills with Razor, and deliver a template markup syntax that enables an awesome HTML construction workflow with your language of choice.
  • Works with any Text Editor: Razor doesn’t require a specific tool and enables you to be productive in any plain old text editor (notepad works great).
  • Has great Intellisense: While Razor has been designed to not require a specific tool or code editor, it will have awesome statement completion support within Visual Studio. We’ll be updating Visual Studio 2010 and Visual Web Developer 2010 to have full editor intellisense for it.
  • Unit Testable: The new view engine implementation will support the ability to unit test views (without requiring a controller or web-server, and can be hosted in any unit test project – no special app-domain required).

Now, the general problem I have with Razor is that the simple, solitary @ prefix works in so few of the on-view coding situations that extra symbols are required to remove the code/markup ambiguity, and the sheer number of these extra token combinations entirely removes the simplicity that Razor promises.

Whereas the older 'code nugget' (or 'webforms') syntax had but two forms:

<% … %>

and

<%: … %>

Razor has many, many forms. In fact, Phil Haack (who I believe worked on the MVC implementation of Razor) has a cheat sheet which lists 19 different forms. Am I expected to memorise these rather than the two simple forms for the older syntax? Furthermore, reading the comments to Phil's article shows even more forms which need to be known.

Some examples

In this example, Razor objects to the third @ - the one prefixing !String.IsNullOrWhiteSpace

Why?

@foreach (var link in Model.Links.Items)
{
    @!String.IsNullOrWhiteSpace(link.Comment)
                            ? link.Comment
                            : link.Url
    
}

A solution to the above is to wrap the instruction in parentheses, like so

@foreach (var link in Model.Links.Items)
{
    @(!String.IsNullOrWhiteSpace(link.Comment)
                            ? link.Comment
                            : link.Url)
    
}

Is Razor not intelligent enough to realise that the ! is a valid syntax symbol?

Let’s change the !String.IsNullOrWhiteSpace logic; why does the foreach require an @, but an if statement doesn't? Both are preceded by a closing HTML tag.

@foreach (var link in Model.Links.Items)
{
    @link.Url
    if (!String.IsNullOrWhiteSpace(link.Comment))
    {
        @link.Comment
    }
}

And if I put the <p> inside the foreach then the @ symbols must be moved.

@foreach (var link in Model.Links.Items)
{
    

        @link.Url         @if (!String.IsNullOrWhiteSpace(link.Comment))         {             @link.Comment         }     

}

A different situation now. I can write this

@{var dtD = Model.CommonOrder.Deadline;}
@dtD.ToString("dddd"), @dtD.ToShortDateString(), @dtD.ToShortTimeString()
@if (Model.ShouldShowDeadlineString)
{
    <br />
    @Model.CommonOrder.Deadline.ToDeadlineString()
}

But if I wish to wrap the results of that ToDeadlineString() call in parentheses, I can't.

@{var dtD = Model.CommonOrder.Deadline;}
@dtD.ToString("dddd"), @dtD.ToShortDateString(), @dtD.ToShortTimeString()
@if (Model.ShouldShowDeadlineString)
{
    <br />
    (@Model.CommonOrder.Deadline.ToDeadlineString())
}

Which I had to solve with

<text>(</text>@Model.CommonOrder.Deadline.ToDeadlineString()<text>)</text>

And this is supposed to be saving me keystrokes.

Moving on... Razor allows this

@if (!Model.Delivered.HasValue)
{
    (@Model.Countdown.ToDeadlineString())
}

But apparently doesn't allow this

@if (Model.ShouldShowDeadlineString)
{
    <br />
    var strDeadline = Model.CommonOrder.Deadline.ToDeadlineString();
    (@strDeadline)
}

And here's another: what's wrong with having @ in front of if (Model.Count > 1)?

@if (Model.JobTypeId == 3)
{
    
    

        @Model.TextStyle.OrderObject.AmountDesc     

    @if (Model.Count > 1)     {                  

            @Model.Count         

    } }

And another: if Razor is supposed to be sophisticated enough to know when I've gone from code to HTML or vice versa, why does it interpret .Phone as a literal string?

@((CustomerManagement.Company) ViewBag.Tenant).Phone

And in this example, why can't I have text after this closing </div>? Why does it tell me that there's a missing ';'?

@Html.TextBoxFor(m => m.Title)
Should not be longer than 60 characters

Conclusion

While I accept that there are probably rational, perhaps even trivial answers to all of the above, there’s no denying that the older syntax, with its two simple forms, was simpler and required a lot less look-up to find which arcane syntax is required for a very specific circumstance. ScottGu may be correct in asserting that Razor views are easier to unit test, and while I don't buy that it has better intellisense than exists in or which could have been implemented into the older syntax, I disagree with his other points: I simply don't agree that Razor is more compact, expressive or fluid (none of the above), I disagree that it's easy to learn because after several years I still run into problems which require using an extended cheat sheet or scouring Stack Overflow.

And nor do I appreciate what Razor offers in terms of document flow. By requiring 'only' a simple '@' prefix and then being able to detect when the instruction has completed and we're back into markup, Razor is supposed to encourage us to write our HTML documents without ugly code blocks. But too often I've had to resort to typing <text>…</text> or some other obfuscating method.