ASP.NET MVC 3: Razor’s @: and <text> syntax

This is another in a series of posts I’m doing that cover some of the new ASP.NET MVC 3 features:

In today’s post I’m going to discuss two useful syntactical features of the new Razor view-engine – the @: and <text> syntax support.

Fluid Coding with Razor

ASP.NET MVC 3 ships with a new view-engine option called “Razor” (in addition to the existing .aspx view engine).  You can learn more about Razor, why we are introducing it, and the syntax it supports from my Introducing Razor blog post. 

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, 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.

For example, the Razor snippet below can be used to iterate a list of products:

image

When run, it generates output like:

image 

One of the techniques that Razor uses to implicitly identify when a code block ends is to look for tag/element content to denote the beginning of a content region.  For example, in the code snippet above Razor automatically treated the inner <li></li> block within our foreach loop as an HTML content block because it saw the opening <li> tag sequence and knew that it couldn’t be valid C#. 

This particular technique – using tags to identify content blocks within code – is one of the key ingredients that makes Razor so clean and productive with scenarios involving HTML creation.

Using @: to explicitly indicate the start of content

Not all content container blocks start with a tag element tag, though, and there are scenarios where the Razor parser can’t implicitly detect a content block.

Razor addresses this by enabling you to explicitly indicate the beginning of a line of content by using the @: character sequence within a code block.  The @: sequence indicates that the line of content that follows should be treated as a content block:

image

As a more practical example, the below snippet demonstrates how we could output a “(Out of Stock!)” message next to our product name if the product is out of stock:

image

Because I am not wrapping the (Out of Stock!) message in an HTML tag element, Razor can’t implicitly determine that the content within the @if block is the start of a content block.  We are using the @: character sequence to explicitly indicate that this line within our code block should be treated as content.

Using Code Nuggets within @: content blocks

In addition to outputting static content, you can also have code nuggets embedded within a content block that is initiated using a @: character sequence. 

For example, we have two @: sequences in the code snippet below:

image

Notice how within the second @: sequence we are emitting the number of units left within the content block (e.g. - “(Only 3 left!”). We are doing this by embedding a @p.UnitsInStock code nugget within the line of content.

Multiple Lines of Content

Razor makes it easy to have multiple lines of content wrapped in an HTML element.  For example, below the inner content of our @if container is wrapped in an HTML <p> element – which will cause Razor to treat it as content:

image

For scenarios where the multiple lines of content are not wrapped by an outer HTML element, you can use multiple @: sequences:

image

Alternatively, Razor also allows you to use a <text> element to explicitly identify content:

image

The <text> tag is an element that is treated specially by Razor. It causes Razor to interpret the inner contents of the <text> block as content, and to not render the containing <text> tag element (meaning only the inner contents of the <text> element will be rendered – the tag itself will not).  This makes it convenient when you want to render multi-line content blocks that are not wrapped by an HTML element. 

The <text> element can also optionally be used to denote single-lines of content, if you prefer it to the more concise @: sequence:

image

The above code will render the same output as the @: version we looked at earlier.  Razor will automatically omit the <text> wrapping element from the output and just render the content within it. 

Summary

Razor enables a clean and concise templating syntax that enables a very fluid coding workflow.  Razor’s smart detection of <tag> elements to identify the beginning of content regions is one of the reasons that the Razor approach works so well with HTML generation scenarios, and it enables you to avoid having to explicitly mark the beginning/ending of content regions in about 95% of if/else and foreach scenarios.

Razor’s @: and <text> syntax can then be used for scenarios where you want to avoid using an HTML element within a code container block, and need to more explicitly denote a content region.

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

43 Comments

  • This is great, I do not need anymore to embed my content inside a span tag for Razor to handle it as text!

  • Hi, Scott!

    Earlier, you promise to show us an implementation of nested layouts.

  • This is all great. Makes me think of a feature request too!

    For multiple lines, in many times those are going to be html tag. Why not support @ inside code blocks to mean content surrounded with tag? (where "sample" is anything ever)

    Example:
    @if(p.UnitsInStock == 0) {
    @Out Of Stock!
    }

    What do you think?

  • Also, are the "{...}" required for "if", "for" in the above examples?
    ex: can I write this?
    @if(p.UnitsInStock == 0) Out of stock!

    BTW, in previous comment, I knew the same thing can be achieved by @: - To make it clear, here is another one:

    @if(p.UnitsInStock == 0) {
    @
    This product is out of stock.

    Please check back another time!


    }

  • good article about tag. It is more useful than @:

  • Thanks Scott. This solves our issue!

  • @Mohamed

    What would be the point of doing that? If the text is wrapped with an HTML tag - Razor implictly understands that it's markup.. ie:

    @if(p.UnitsInStock == 0) {
    Out Of Stock!
    }

    would simply render
    Out Of Stock!

    to the page if UnitsInStock was 0

    The point of @ is purely incase you don't HAVE an HTML tag wrapping that content.. ie

    @Out of Stock!

    would render as

    Out of Stock!

    (ie, no surrounding tags)

  • @andrewdavey,

    >>>>>>> Could a future version of Razor support an extensible syntax? E.g. allowing different plugins to be triggered by the character following the "@". We have "@*" and "@:" already, I could imagine wanting another symbol that directly accesses the ViewBag or Model.

    That would certainly be a nice option to support in the future. Thanks for suggesting it!

    Scott

  • @w!ldc@t

    >>>>>> Earlier, you promise to show us an implementation of nested layouts.

    Still on my list to do! :-)

    Thanks,

    Scott

  • 1. So nice and clean. All ASP.NET MVC Book Authors should update their upcoming books to use Razor instead of Web Form View Engine.
    2. I know the MVC team is too busy fixing bugs and add performance to RTM version but all MVC folks looking for ASP.NET MVC RC2 (or at least RC) source code.
    3. Your Blog is the only cure to MVC 3 and Razor documentation leakage, keep up the great work.

  • @Mohamed Meligy,

    Makes me think of a feature request too!

    >>>>>> @if(p.UnitsInStock == 0) {
    >>>>>> @
    >>>>>> This product is out of stock.

    >>>>>> Please check back another time!
    >>>>>>

    >>>>>> }

    The cool thing is that you don't need this feature :-) You can just do this today and it will work fine:

    @if(p.UnitsInStock == 0) {

    This product is out of stock.

    Please check back another time!


    }

    Razor will use the to identify that the inner region is content. No need to specify anything else. I updated my post above to include a sample that calls this out more clearly. The and @: syntax elements are only required for scenarios in which no containing HTML tag surrounds the content.

    Hope this helps,

    Scott

  • it's really easy to use, and I like the idea by andrewdavey, I think you need to think about it!

    Sorry for bad English I am from Ukraine.

  • @w!ldc@t
    I've blogged about nested layout pages here:
    http://aboutcode.net/2010/11/08/nested-layout-pages-in-razor.html

    The post was pre-RC2, but the general idea works :)

  • But in HTML 5 can't you invent a tag called ?
    How would you then use your tag?

  • Nice feature, thank you very much!

  • can we omit the {braces} on single line if statements?

  • Ran into a problem that this blog entry clarified. Thank you. Now do you have anything for this cold? Jk.

  • That's great. But days and days, we have a lot of symbol for short writing, It will make me not remember more than text.

  • @Graham,

    The tag is only a marker for Razor, it won't ever be seen by the browser.

  • Hi Scott,

    Thanks for working hard to release some fantastic products/updates this year. How about doing a year in review kind of post that highlights the most important releases/updates/posts from your blog etc for 2010. And also a little about what can we expect next year.

    Thanks.

  • @Mohammed,

    >>>>>>> Also, are the "{...}" required for "if", "for" in the above examples?

    Yes - the braces are required for C# as Razor uses them to identify the scope of the content block.

    Thanks,

    Scott

  • @mike,

    >>>>>>> can we omit the {braces} on single line if statements?

    You do need the braces - as we use those within Razor to identify the scope of the content block.

    Hope this helps,

    Scott

  • What are your thoughts on Razor (as default) on T4? Should it be done and when?

  • Thanks for the great post, as always.

    Could you explain a little more why the "@:" only applies to a single line rather than extending until it hits something that closes the "container context" like the ending "}"? If it's due to technical/parsing limitations, maybe an option for something like "@:{ foo }" could work for multi-line blocks of text/markup.

    Also, I would love to see options to strip whitespace. It makes sense to structure the code/markup with nice indenting and line breaks, but then from a download/browser perspective it usually makes sense to have as little whitespace rendered as possible.

  • I need some help with the syntax for creating Id's.
    How can I append @i to id="x"


    @for (int i = 1; i < 5; i++)
    {



    Label textasasasas x



    }

  • Cool stuff, never have enough of those MVC goodies. Thanks for all the hard work for the community.

  • Is it possible to localize the text after @: ?

  • Thanks Scott - I'm already loving using Razor and it's good to discover all the additional things I could be using!

    My big request for extending "@" would be some sort of "@!" which would stop the Html encoding from happening

    - e.g. if I have a block of pre-encoded HTML foo="bar
    " then I'd like to be able to write it using:
    @!foo
    rather than:
    @(new HtmlString(foo))
    This is especially to work with pre-existing code blocks and database content
    Thanks again!

  • Hi Scott,

    Love to read your blogs. Great work.

    Is there a chance that you could comment on all the late bound code (Code that is resolved at runtime) that this MVC framework introduces?

    What is the reason for this approach? Is this really what people wants?
    I have just created a new website using the MVC3 template and its great all the out of the box stuff that this creates but I dont at all fancy the late bound code this template uses. Its hard to debug and maintain.

    Examples on late bound code:
    1. ViewBag.Title (Set in Views and used in _layout)
    2. @Html.Partial("_LogOnPartial") used in _layout
    3. @Html.ActionLink("Register", "Register") (I know this is not likely to change name but what if it does and you forget to change it just one place?)

    All these issues results in runtime errors but could in the "good" old days have been caught by the compiler by doing following..

    1. Using Page.Title or a extension method on Page
    2. Using @Register and tag
    3. This is pretty much the same but would not resolve in a runtime error but a "not found" page. I dont know which one is better

    Am I the only one with this concern?

  • @Marting Nyborg

    You could use a variable to store the id


    @for (int i = 1; i < 5; i++)
    {



    @{string idName = "x" + i;
    }
    Label textasasasas @idName



    }


    Hope this helps

    Grant

  • Is there any chance we will see the Razor syntax been available inside traditional aspx/ascx files? Having suffered with for so long this looks like manna from heaven.

  • Dear Scott,
    I really hope you guys fixed or build more Silverlight features as fast as you do with ASP.NET MVC.
    Sorry to spoil here, but as me and my team have chosen a technology, Silverlight.
    We expect to see it geared toward a full-fledge enterprise application framework, Fast!
    I feel like Silverlight is still a second-rate priority to you.
    Silverlight FireStarter event is just another hopeless promise to me and cannot give me rest.
    While someone sees HTML5 is a threat to SL, I see ASP.NET MVC framework is a true threat.
    It's the battle of plug-ins or pure html applications.
    And I hope we won't have to fight each other but MS should support them both (more) equally.

  • It seems like it would have been a little nicer if was something like @: :@ instead. i.e. make it work kind of like /* */ comments. It seems like the syntax would have been a little more consistent then. Whereas the text tags make it seem like it's outputting HTML tags. Not a big deal, just a thought.

  • I'm curious how this format handles email addresses, and variables that are space sensitive.
    For example: someone@someplace.net vs. (or another similar situation).
    Would you have to specially escape one or more of those?

  • Razor is just awesome.

  • I feel that Razor will make the process slow, isn't it so? Because, first Razor has to parse the code then it will convert it in DOM and finally render. Also, as you have explained many ways to content so suppose if we write multiple nested contents, then will it not make Razor overhead and Razor will slow down being busy on parsing only.

  • Razor and the default asp.net view engine should lose the braces in if sentences, period. It is a shame that this is needed, when PHP, RoR and others don't need them and not only for one line block inside IFs. It's a matter of putting more effort into the parser and less into dozens of questionable features. Until this is achieved no other feature will be able to boost the productivity to the same degree as this change would. And until this happens there should be changes made to the VS so that it would format the code in views better because apparently you can't force it to put the brace on the same line with the condition, no matter what you set in options, it puts braces under it.
    That's what I have to say about braces. Other than that, besides Razor I don't see a single feature in MVC3 that really boosts productivity or introduces some really interesting groundbreaking changes.

  • Just the the thing i was waiting for, Razor enables you to concentrate on the job @ hand rather than doodling around html tags.

  • Can Razor layout like frameset?

  • Thanks very much admin .. :)

  • Thanks very much for your excellent blog, it's easily my favorite read :-)

    I have been toying with a problem with Razor in a small MVC3 application, that I haven't been able to find a solution to.

    Basically, I want to iterate over a list and create a table which will list every item, but with two items in each row.

    I have created a foreach and counter like this
    @{
    var counter = 0;
    }

    @foreach (var category in ViewBag.Categories)
    {
    counter++;


    @category.Description


    if (counter % 2 == 0)
    {




    }
    }

    An exception is thrown once it reaches my section (The "tr" element was not closed. All elements must be either self-closing or have a matching end tag.).

    Do you have any hints on how one can create a nested level in Razor syntax and avoid this begin/end tag matching?

    Best Regards
    Kenneth

  • @Kenneth,

    >>>>>>> An exception is thrown once it reaches my section (The "tr" element was not closed. All elements must be either self-closing or have a matching end tag.).

    Can you try this instead to see if it works:

    if (counter % 2 == 0) {
    @:
    }

    Let me know if you still have problems with that.

    Thanks,

    Scott

  • Scott, there seems to be some issues with auto-formatting (Ctrl+K+D) and certain constructs in Razor:


    @if (Model.Calendars.Count() > 1) {
    @: Display Calendar: @Html.DropDownList("CalendarSelect", new SelectList(Model.Calendars, "CalendarId", "Name", Model.Calendars.First().CalendarId))
    }


    Every time the above code gets auto-formatted, the closing curly brace gets indented one more (so repeated auto-formats indent that line more and more).

    I'd have gone through proper bug reporting channels, but I can't find any official way to report them; is there one?

Comments have been disabled for this content.