Razor syntax

By Taylor Mullen and Rick Anderson

What is Razor?

Razor is a markup syntax for embedding server based code into web pages. The Razor syntax consists of Razor markup, C# and HTML. Files containing Razor generally have a .cshtml file extension.

Rendering HTML

The default Razor language is HTML. Rendering HTML from Razor is no different than in an HTML file. A Razor file with the following markup:

<p>Hello World</p>

Is rendered unchanged as <p>Hello World</p> by the server.

Razor syntax

Razor supports C# and uses the @ symbol to transition from HTML to C#. Razor evaluates C# expressions and renders them in the HTML output. Razor can transition from HTML into C# or into Razor specific markup. When an @ symbol is followed by a Razor reserved keyword it transitions into Razor specific markup, otherwise it transitions into plain C# .

HTML containing @ symbols may need to be escaped with a second @ symbol. For example:

<p>@@Username</p>

would render the following HTML:

<p>@Username</p>

HTML attributes and content containing email addresses don’t treat the @ symbol as a transition character.

<a href="mailto:Support@contoso.com">Support@contoso.com</a>

Implicit Razor expressions

Implicit Razor expressions start with @ followed by C# code. For example:

<p>@DateTime.Now</p>
<p>@DateTime.IsLeapYear(2016)</p>

With the exception of the C# await keyword implicit expressions must not contain spaces. For example, you can intermingle spaces as long as the C# statement has a clear ending:

<p>@await DoSomething("hello", "world")</p>

Explicit Razor expressions

Explicit Razor expressions consists of an @ symbol with balanced parenthesis. For example, to render last week's time:

<p>Last week this time: @(DateTime.Now - TimeSpan.FromDays(7))</p>

Any content within the @() parenthesis is evaluated and rendered to the output.

Implicit expressions generally cannot contain spaces. For example, in the code below, one week is not subtracted from the current time:

<p>Last week: @DateTime.Now - TimeSpan.FromDays(7)</p>

Which renders the following HTML:

<p>Last week: 7/7/2016 4:39:52 PM - TimeSpan.FromDays(7)</p>

You can use an explicit expression to concatenate text with an expression result:

@{
    var joe = new Person("Joe", 33);
 }

<p>Age@(joe.Age)</p>

Without the explicit expression, <p>Age@joe.Age</p> would be treated as an email address and <p>Age@joe.Age</p> would be rendered. When written as an explicit expression, <p>Age33</p> is rendered.

Expression encoding

C# expressions that evaluate to a string are HTML encoded. C# expressions that evaluate to IHtmlContent are rendered directly through IHtmlContent.WriteTo. C# expressions that don't evaluate to IHtmlContent are converted to a string (by ToString) and encoded before they are rendered. For example, the following Razor markup:

@("<span>Hello World</span>")

Renders this HTML:

&lt;span&gt;Hello World&lt;/span&gt;

Which the browser renders as:

<span>Hello World</span>

HtmlHelper Raw output is not encoded but rendered as HTML markup.

Warning

Using HtmlHelper.Raw on unsanitized user input is a security risk. User input might contain malicious JavaScript or other exploits. Sanitizing user input is difficult, avoid using HtmlHelper.Raw on user input.

The following Razor markup:

@Html.Raw("<span>Hello World</span>")

Renders this HTML:

<span>Hello World</span>

Razor code blocks

Razor code blocks start with @ and are enclosed by {}. Unlike expressions, C# code inside code blocks is not rendered. Code blocks and expressions in a Razor page share the same scope and are defined in order (that is, declarations in a code block will be in scope for later code blocks and expressions).

@{
    var output = "Hello World";
}

<p>The rendered result: @output</p>

Would render:

<p>The rendered result: Hello World</p>

Implicit transitions

The default language in a code block is C#, but you can transition back to HTML. HTML within a code block will transition back into rendering HTML:

@{
    var inCSharp = true;
    <p>Now in HTML, was in C# @inCSharp</p>
}

Explicit delimited transition

To define a sub-section of a code block that should render HTML, surround the characters to be rendered with the Razor <text> tag:

@for (var i = 0; i < people.Length; i++)
{
    var person = people[i];
    <text>Name: @person.Name</text>
}

You generally use this approach when you want to render HTML that is not surrounded by an HTML tag. Without an HTML or Razor tag, you get a Razor runtime error.

Explicit Line Transition with @:

To render the rest of an entire line as HTML inside a code block, use the @: syntax:

@for (var i = 0; i < people.Length; i++)
{
    var person = people[i];
    @:Name: @person.Name
}

Without the @: in the code above, you'd get a Razor run time error.

Control Structures

Control structures are an extension of code blocks. All aspects of code blocks (transitioning to markup, inline C#) also apply to the following structures.

Conditionals @if, else if, else and @switch

The @if family controls when code runs:

@if (value % 2 == 0)
{
    <p>The value was even</p>
}

else and else if don't require the @ symbol:

@if (value % 2 == 0)
{
    <p>The value was even</p>
}
else if (value >= 1337)
{
    <p>The value is large.</p>
}
else
{
    <p>The value was not large and is odd.</p>
}

You can use a switch statement like this:

@switch (value)
{
    case 1:
        <p>The value is 1!</p>
        break;
    case 1337:
        <p>Your number is 1337!</p>
        break;
    default:
        <p>Your number was not 1 or 1337.</p>
        break;
}

Looping @for, @foreach, @while, and @do while

You can render templated HTML with looping control statements. For example, to render a list of people:

@{
    var people = new Person[]
    {
          new Person("John", 33),
          new Person("Doe", 41),
    };
}

You can use any of the following looping statements:

@for

@for (var i = 0; i < people.Length; i++)
{
    var person = people[i];
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>
}

@foreach

@foreach (var person in people)
{
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>
}

@while

@{ var i = 0; }
@while (i < people.Length)
{
    var person = people[i];
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>

    i++;
}

@do while

@{ var i = 0; }
@do
{
    var person = people[i];
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>

    i++;
} while (i < people.Length);

Compound @using

In C# a using statement is used to ensure an object is disposed. In Razor this same mechanism can be used to create HTML helpers that contain additional content. For instance, we can utilize HTML Helpers to render a form tag with the @using statement:

@using (Html.BeginForm())
{
    <div>
        email:
        <input type="email" id="Email" name="Email" value="" />
        <button type="submit"> Register </button>
    </div>
}

You can also perform scope level actions like the above with Tag Helpers.

@try, catch, finally

Exception handling is similar to C#:

@try
{
    throw new InvalidOperationException("You did something invalid.");
}
catch (Exception ex)
{
    <p>The exception message: @ex.Message</p>
}
finally
{
    <p>The finally statement.</p>
}

@lock

Razor has the capability to protect critical sections with lock statements:

@lock (SomeLock)
{
    // Do critical section work
}

Comments

Razor supports C# and HTML comments. The following markup:

@{
    /* C# comment. */
    // Another C# comment.
}
<!-- HTML comment -->

Is rendered by the server as:

<!-- HTML comment -->

Razor comments are removed by the server before the page is rendered. Razor uses @* *@ to delimit comments. The following code is commented out, so the server will not render any markup:

 @*
 @{
     /* C# comment. */
     // Another C# comment.
 }
 <!-- HTML comment -->
*@

Directives

Razor directives are represented by implicit expressions with reserved keywords following the @ symbol. A directive will typically change the way a page is parsed or enable different functionality within your Razor page.

Understanding how Razor generates code for a view will make it easier to understand how directives work. A Razor page is used to generate a C# file. For example, this Razor page:

@{
    var output = "Hello World";
}

<div>Output: @output</div>

Generates a class similar to the following:

public class _Views_Something_cshtml : RazorPage<dynamic>
{
    public override async Task ExecuteAsync()
    {
        var output = "Hello World";

        WriteLiteral("/r/n<div>Output: ");
        Write(output);
        WriteLiteral("</div>");
    }
}

Viewing the Razor C# class generated for a view explains how to view this generated class.

@using

The @using directive will add the c# using directive to the generated razor page:

@using System.IO
@{
    var dir = Directory.GetCurrentDirectory();
}
<p>@dir</p>

@model

The @model directive allows you to specify the type of the model passed to your Razor page. It uses the following syntax:

@model TypeNameOfModel

For example, if you create an ASP.NET Core MVC app with individual user accounts, the Views/Account/Login.cshtml Razor view contains the following model declaration:

@model LoginViewModel

In the preceding class example, the class generated inherits from RazorPage<dynamic>. By adding an @model you control what’s inherited. For example

@model LoginViewModel

Generates the following class

public class _Views_Account_Login_cshtml : RazorPage<LoginViewModel>

Razor pages expose a Model property for accessing the model passed to the page.

<div>The Login Email: @Model.Email</div>

The @model directive specified the type of this property (by specifying the T in RazorPage<T> that the generated class for your page derives from). If you don't specify the @model directive the Model property will be of type dynamic. The value of the model is passed from the controller to the view. See Strongly typed models and the @model keyword for more information.

@inherits

The @inherits directive gives you full control of the class your Razor page inherits:

@inherits TypeNameOfClassToInheritFrom

For instance, let’s say we had the following custom Razor page type:

using Microsoft.AspNetCore.Mvc.Razor;

public abstract class CustomRazorPage<TModel> : RazorPage<TModel>
{
    public string CustomText { get; } = "Hello World.";
}

The following Razor would generate <div>Custom text: Hello World</div>.

@inherits CustomRazorPage<TModel>

<div>Custom text: @CustomText</div>

You can't use @model and @inherits on the same page. You can have @inherits in a _ViewImports.cshtml file that the Razor page imports. For example, if your Razor view imported the following _ViewImports.cshtml file:

@inherits CustomRazorPage<TModel>

The following strongly typed Razor page

@inherits CustomRazorPage<TModel>

<div>The Login Email: @Model.Email</div>
<div>Custom text: @CustomText</div>

Generates this HTML markup:

<div>The Login Email: Rick@contoso.com</div>
<div>Custom text: Hello World</div>

When passed "Rick@contoso.com" in the model:

See Layout for more information.

@inject

The @inject directive enables you to inject a service from your service container into your Razor page for use. See Dependency injection into views.

@functions

The @functions directive enables you to add function level content to your Razor page. The syntax is:

@functions { // C# Code }

For example:

@functions {
    public string GetHello()
    {
        return "Hello";
    }
}

<div>From method: @GetHello()</div> 

Generates the following HTML markup:

<div>From method: Hello</div>

The generated Razor C# looks like:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Razor;

public class _Views_Home_Test_cshtml : RazorPage<dynamic>
{
    // Functions placed between here 
    public string GetHello()
    {
        return "Hello";
    }
    // And here.
#pragma warning disable 1998
    public override async Task ExecuteAsync()
    {
        WriteLiteral("\r\n<div>From method: ");
        Write(GetHello());
        WriteLiteral("</div>\r\n");
    }
#pragma warning restore 1998

@section

The @section directive is used in conjunction with the layout page to enable views to render content in different parts of the rendered HTML page. See Sections for more information.

Tag Helpers

The following Tag Helpers directives are detailed in the links provided.

Razor reserved keywords

Razor keywords

  • functions
  • inherits
  • model
  • section
  • helper (Not supported by ASP.NET Core.)

Razor keywords can be escaped with @(Razor Keyword), for example @(functions). See the complete sample below.

C# Razor keywords

  • case
  • do
  • default
  • for
  • foreach
  • if
  • lock
  • switch
  • try
  • using
  • while

C# Razor keywords need to be double escaped with @(@C# Razor Keyword), for example @(@case). The first @ escapes the Razor parser, the second @ escapes the C# parser. See the complete sample below.

Reserved keywords not used by Razor

  • namespace
  • class

Viewing the Razor C# class generated for a view

Add the following class to your ASP.NET Core MVC project:

using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

public class CustomCompilationService : DefaultRoslynCompilationService, ICompilationService
{
    public CustomCompilationService(ApplicationPartManager partManager, 
        IOptions<RazorViewEngineOptions> optionsAccessor, 
        IRazorViewEngineFileProviderAccessor fileProviderAccessor, 
        ILoggerFactory loggerFactory) 
        : base(partManager, optionsAccessor, fileProviderAccessor, loggerFactory)
    {
    }

    CompilationResult ICompilationService.Compile(RelativeFileInfo fileInfo, 
        string compilationContent)
    {
        return base.Compile(fileInfo, compilationContent);
    }
}

Override the ICompilationService added by MVC with the above class;

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<ICompilationService, CustomCompilationService>();
}

Set a break point on the Compile method of CustomCompilationService and view compilationContent.

Text Visualizer view of compilationContent

Note

View lookups are case sensitive. If your controller routing seeks a view named Index (Index.cshtml) but you've named your view file index (index.cshtml), you'll receive an exception: InvalidOperationException: The view 'Index' was not found.