Razor Syntax

How @ switches a .cshtml file from HTML into C#, how to loop and branch in a template, and the HTML encoding you get by default.

Syntax@expression @(explicit expression) @{ code block } @* comment *@

A .cshtml file is HTML with C# mixed into it. The mixing syntax is called Razor. Everything in the file is plain HTML until an @ appears. The @ switches into C#, and the compiler works out where the C# ends and the HTML starts again.

Expressions

@Model.Name is an implicit expression: the value is turned into text and written into the page. An implicit expression stops at the first space, and it cannot contain a generic type argument, because < looks like the start of a tag. For those cases use an explicit expression and wrap the C# in parentheses: @(count * 2). The two forms are the same thing. The parentheses only mark where the C# ends.

Blocks and control structures

@{ ... } is a code block. It runs C# and writes nothing by itself. @if, @foreach, @for, @while, @switch and @try are ordinary C# statements with HTML inside their braces; else and case need no further @. @* ... *@ is a Razor comment and is removed before the page is sent, unlike <!-- -->, which the browser receives.

Encoding

A string written by an expression is HTML encoded, so < becomes &lt; and text a visitor typed cannot smuggle in tags. @Html.Raw(value) skips the encoding. Use it only on markup you built yourself.

.cshtml files are compiled when the project is built. Runtime compilation of Razor files became obsolete in .NET 10; use .NET Hot Reload to see template edits while the app is running.

Example

Example · csharp
@* Views/Home/Index.cshtml. The action passed a string[] of pet names. *@
@model string[]

@{
    // A code block runs C# and prints nothing on its own.
    var count = Model.Length;
    var markup = "<b>bold</b>";
}

<h1>Pets</h1>
<p>You have @count pets.</p>

@if (count == 0)
{
    <p>None yet.</p>
}
else
{
    <ul>
        @foreach (var name in Model)
        {
            <li>@name</li>
        }
    </ul>
}

@* Implicit on the left, explicit on the right. *@
<p>@count doubled is @(count * 2)</p>

@* Strings are encoded, so the tags arrive as visible text. *@
<p>@markup</p>

@*
Renders for Model = ["Mia", "Bo"], ignoring whitespace:
<h1>Pets</h1>
<p>You have 2 pets.</p>
<ul><li>Mia</li><li>Bo</li></ul>
<p>2 doubled is 4</p>
<p>&lt;b&gt;bold&lt;/b&gt;</p>
*@

When to use it

  • Render a table row for every item in a list the controller fetched.
  • Show an "edit" link only when the model says the viewer owns the item.
  • Print text a visitor submitted without letting it inject HTML into the page.

More examples

Encoding by default, and Html.Raw

This is the difference between a working page and a cross-site scripting hole. Reach for Html.Raw only when a trusted part of your own code produced the markup, for example a snippet rendered from your own template, and never on anything a visitor sent.

Example · cshtml
@* Model holds text a visitor typed into a comment box. *@
@model string

@* Encoded. Whatever the text contains, it renders as text. *@
<p>@Model</p>

@* Not encoded. The characters go through untouched. *@
<p>@Html.Raw("<em>Written by us, not by a visitor</em>")</p>

@* For Model = "<script>alert(1)</script>" the first paragraph renders:
<p>&lt;script&gt;alert(1)&lt;/script&gt;</p>
*@

A literal @ sign, and the two kinds of comment

Needed whenever a page prints CSS at-rules, social handles or a price in a currency written with @. Email addresses are a special case: Razor leaves an @ alone when it sits between two words, so mailto links need no escaping.

Example · cshtml
@* A Razor comment. It is stripped before the response is written. *@
<!-- An HTML comment. The browser receives this one. -->

<p>Write @@media to print one @ sign.</p>
<p><a href="mailto:[email protected]">[email protected]</a></p>

@*
Renders:
<!-- An HTML comment. The browser receives this one. -->
<p>Write @media to print one @ sign.</p>
<p><a href="mailto:[email protected]">[email protected]</a></p>
*@

A local function used as a small template

Useful when the same few lines of markup repeat two or three times in one file and a separate partial file would be overkill. The call sits inside a code block because the function returns nothing, so there is no value for @ to write.

Example · cshtml
@model int[]

@{
    var total = Model.Sum();

    // A local function declared in a code block may contain markup.
    void Row(string label, int amount)
    {
        <tr><td>@label</td><td>@amount</td></tr>
    }
}

<table>
    <tbody>
        @{ Row("Items", Model.Length); }
        @{ Row("Total", total); }
    </tbody>
</table>

Discussion

  • Be the first to comment on this lesson.