Razor provides two ways to differentiate code from markup: code nuggets and code blocks.
Code nuggets are simple expressions that are evaluated and rendered inline. They can be mixed with text and look like this:
Not Logged In: @Html.ActionLink("Login", "Login")
The expression begins immediately after the @
symbol, and Razor is smart enough to know
that the closing parenthesis indicates the end of this particular
statement. The previous example will render this output:
Not Logged In: <a href="/Login">Login</a>
Notice that code nuggets must always return markup for the view to
render. If you write a code nugget that does not return anything (i.e.
returns void
), you will receive an
error when the view executes.
A code block is a section of the view that contains strictly code
rather than a combination of markup and code. Razor defines a code block
as any section of a Razor template
wrapped in @{ }
characters. The
@{
characters mark the beginning of
the block, followed by any number of lines of code. The }
character closes the code block.
Keep in mind that the code within a code block is not like code in
a code nugget. It is fully-formed code that must follow the rules of the
current language; for example, each line of code written in C# must
include a semicolon (;
) at the end,
just as if it lived within a class in a .cs
file.
Here is an example of a typical code block:
@{ LayoutPage = "~/Views/Shared/_Layout.cshtml"; View.Title = "Product Details for " + Model.ProductName; }
Code blocks do not render anything to the page. Instead, they
allow you to write arbitrary code that requires no return value.
Variables defined within code blocks may be used by code nuggets in the
same scope. That is, variables defined within the scope of a foreach
loop or similar container will only be
accessible within that container. Variables that are defined at the page
level (not in any kind of container) will be accessible to any other
code blocks or code nuggets in the page.
To clarify this, take a look at a view with a few variables defined at different scopes:
@{ // The customer and order variables are // available to the entire page var customer = Model.Customer; var order = Model.Order; } <h1>@customer.Name' Order Details<h1> <div class="items"> <!-- Loop through the Items property on the order variable --> @foreach(var item in order.Items) { <!-- The item variable is only available within the foreach loop --> <div> <!-- A hyperlink builds a URL to the Order Item page using the Order ID and the Item ID --> <a href="/orders/@order.ID/@item.ID">@item.Name</a> </div> } <!-- This will throw an error: the item variable does not exist at this scope! --> <div>Last Item: @item.Name</div> </div>
Code blocks are a means to execute code within a template and do not render anything to the view. In direct contrast to the way that code nuggets must provide a return value for the view to render, the view will completely ignore values that a code block returns.
The @
symbol is the heart of
the Razor syntax, the character that Razor uses to differentiate code
from markup. The @
symbol marks a
point at which the developer intends to switch from markup to code. In
simple cases, no additional characters are needed to indicate when the
code stops and the markup resumes. Razor’s intelligent parser determines
which parts of the template are code and which are markup.
What makes a valid code statement? Razor uses the following
algorithm to find the end of a code statement once it reads the @
symbol trigger:
Read to the end of a valid identifier (i.e., a C# or VB keyword) or variable name.
If the next character is an opening bracket (
(
or[
)…Keep parsing until the corresponding closing bracket is located. Nested brackets are also tracked to avoid premature closing of a block.
Loop back to #2.
If the next character is a
.
(period) and precedes a valid identifier, jump to #1.Complete the code statement and continue processing the rest of the markup.
Razor relies on the current language’s syntax to determine the end of a code statement. Razor also attempts to “read forward,” checking if the upcoming content resembles code or markup. The specifics depend on the language currently in use (C# or VB).
Here’s a typical Razor snippet:
@foreach(var item in order.Items) { <li>@item.Name</li> }
The first line initializes the loop variables and opens the loop
with an opening bracket; the second line renders markup; and the third
line contains the closing bracket to end the loop. There is a clear
transition between code and markup because the second line begins with
an <li>
tag that is clearly an
HTML element and the third line is clearly the foreach
loop’s closing tag.
In this example there is another line of code following the
initial opening foreach
line:
@foreach(var item in order.Items) { var itemName = item.Name; <li>@itemName</li> }
Since the second line follows the variable initialization C#
syntax, Razor continues to correctly interpret this second line as C#
code, as opposed to markup, and executes it as such. As it continues
parsing, Razor correctly assumes that the third line is markup and
renders it correctly. The final line is code again: the closing bracket
for the foreach
loop.
Consider a third example, this time with C# generics syntax thrown into the mix:
@foreach(var item in order.Items) { var itemName = GetOrderItemName<string>(item); <li>@itemName</li> }
In this example, the second line contains a generic parameter. While this is perfectly valid C# code, the bracket-based C# generic syntax is practically indistinguishable from HTML. Thus, the Razor parser gets confused and cannot determine whether to interpret the line as code or markup. Razor responds by giving up and throwing an exception.
While Razor’s ability to differentiate between code and markup is generally impressive, this example shows that there are certainly scenarios that it cannot accurately parse. In these scenarios, there are several ways to explicitly state your intent and disambiguate code from markup.
The explicit code nugget syntax (@( )
) allows you to wrap a code statement,
unambiguously marking the beginning and end of the statement. The
explicit code nugget syntax lets you give Razor some guidance about
how your markup should be interpreted.
Here is an example in which Razor incorrectly assumes that the
.
in the filename extension is part
of the code statement, resulting in a call to the (nonexistent)
property Product.Name.jpg
:
<img src="/products/@Product.Name.jpg" />
The explicit code nugget syntax clears things right up, wrapping the code to separate it from content:
<img src="/products/@(Product.Name).jpg" />
The same syntax can be applied to differentiate the generic
parameter in the example at the beginning of this section. In this
example, however, the preceding @
character is not required because the trouble spot is already within a
code statement:
@foreach(var item in order.Items) { var itemName = ( GetOrderItemName<string>(item) ); <li>@itemName</li> }
The @:
character sequence
indicates a transition, telling Razor to assume that the content that
follows the sequence is content, not code. You are still free to use
the @
symbol any time after
transitioning to content mode to execute code, just as in any other
part of the Razor template. The following example shows the @:
character sequence in action:
@if(User.IsAuthenticated) { @:Hello, @User.Name! } else { @:Please login }
The conditional markup in this example does not specify any
HTML, so it is difficult for Razor to figure out when or if to
transition to markup mode. After all, how can Razor know whether
“Hello” is a class name or an arbitrary word? The markup in the
if
condition uses the @:
character sequence to specify that
“Hello” is actually content and not code. The same markup then
switches back to code mode to render the value of the User.Name
property. The markup in the
else
condition also uses the
@:
character sequence to indicate
that the text should be rendered verbatim.
The <text>
block is an
alternative to the @:
character
sequence that allows you to denote that an entire portion of a
template is content. <text>
is useful in scenarios where multiple lines of markup can be
interpreted as code or text, such as:
@if(!User.IsAuthenticated) { <text> Guests are not allowed to view this content. Please @Html.ActionLink("login", "Login") to view. </text> }
which produces the following output when the user is not authenticated:
Guests are not allowed to view this content. Please <a href="/Login">login</a> to view.
As you can see, the opening and closing <text>
tags are only used within the
template to mark the beginning and end of the block of content and are
not rendered along with the content. The example also shows that code
statements are still perfectly acceptable within a <text>
block.
There are plenty of circumstances that confuse Razor. By
default, it will assume that ambiguous markup is code. Consider the
@:
character sequence and <text>
blocks as a way to tell Razor
“whenever you are unsure about whether something in this block is code
or content, it is content!”
Get Programming Razor now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.