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.
@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 < 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
* Views/Home/Index.cshtml. The action passed a string[] of pet names. *
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 pets.</p>
(count == 0)
{
<p>None yet.</p>
}
else
{
<ul>
(var name in Model)
{
<li></li>
}
</ul>
}
* Implicit on the left, explicit on the right. *
<p> doubled is (count * 2)</p>
* Strings are encoded, so the tags arrive as visible text. *
<p></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><b>bold</b></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.
@* 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><script>alert(1)</script></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.
@* 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.
@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