Outputting partial elements with ASP.NET Razor

The new ASP.NET MVC 3 also ships with a totally new option for a view engine, Razor. I’ve now been using Razor in a project for couple of months, and yeah, it’s good – but not entirely without problems. Here I’ll cover one of them.

Imagine a scenario where you’re outputting something that may or may not be a link, depending on the conditions. You’d be tempted to write something like this:

@if(linkUri != null) { <a href='@linkUri'> }
Some text
@if(linkUri != null) { </a> }

… only to find out that it doesn’t work. The error message you’ll be getting is probably “The if block is missing a closing "}" character.  Make sure you have a matching "}" character for all the "{" characters within this block, and that none of the "}" characters are being interpreted as markup.” Alternatively, you could get “The foreach block is missing a closing “}”…” or something similar, depending on your enclosing elements.

That’s not really enlightening, and it turns out Razor is smarter than you’d think – and as usual, smart software has a flip side.

You could just balance yourself…

Razor is intended to be written with elements fully enclosed within the C# blocks. Therefore, you might rewrite this as:

@if(linkUri != null) { <a href='@linkUri'>Some text</a> }
else { <text>Some text</text> }

However, such an approach repeats “Some text”, which may be a lengthy expression or even an entire block of HTML, making this rather clumsy. Note that you need the <text>…</text> element to ensure that the else block content gets parsed as HTML instead of C# – the text element will not be present in the resulting HTML, and would be unnecessary if you had any actual tags in there.

Another workaround would be to use the WriteLiteral method and enclose the tags in C# strings, disabling Razor’s parsing logic:

@if(linkUri != null) { WriteLiteral("<a href='" + linkUri + "'>"); }
Some text
@if(linkUri != null) { WriteLiteral("</a>"); }

… but what you really want is @:

Of course, this is a common enough scenario to warrant a syntactic helper. It’s called @:, and it means that the following line is markup, no matter what tags occur. This allows the logic to be written as follows:

@if(linkUri != null) {
  @:<a href='@linkUri'> 

} Some text @if(linkUri != null) { @:</a> }

Unfortunately, as you can see, the @: has a line scope and thus necessitates a few additional line feeds. Despite that, this is rather readable and scales well to complex instances of “Some text”.

Thanks to Andrew Nurse at the Razor team for helping me out with this!

November 17, 2010 · Jouni Heikniemi · No Comments
Tags: ,  · Posted in: .NET, Web

Leave a Reply