Master the Razor syntax you use every day: expressions, code blocks, if and foreach, explicit expressions, comments, escaping the @ symbol, the text tag, and the directives at the top of a view.

Bishal Biswas
Self Learner
The @ symbol switches to C#
Razor has one core rule: @ means βthe next thing is C#β. Everything else is HTML.
<p>Hello, @Model.Name. Today is @DateTime.Now.DayOfWeek.</p>
<p>Hello, Asha. Today is Saturday.</p>
That is an implicit expression. Razor reads the C# after @ until it reaches something that cannot be part of an expression, such as a space or an HTML tag, then switches back to HTML.
Explicit expressions
Sometimes Razor stops too early. This does not work as intended:
<p>Total: @Model.Price * 2</p>
Razor prints @Model.Price, then the literal text * 2, because a space ends the expression. Wrap the C# in parentheses to tell Razor exactly where it ends:
<p>Total: @(Model.Price * 2)</p>
<p>Next year: @(DateTime.Now.Year + 1)</p>
<p>@(Model.InStock ? "In stock" : "Sold out")</p>
Use @( ... ) whenever an expression contains spaces or operators.
Code blocks
A code block runs C# statements without printing anything:
@{
var total = Model.Price * Model.Quantity;
var label = total > 100 ? "Free shipping" : "Standard shipping";
}
<p>@label: @total.ToString("C")</p>
Code blocks are common at the top of a view for setting the page title or preparing values. Try not to put real logic there. If the C# in a view is getting long, the calculation probably belongs in the controller or a view model.
Conditions
@if works like C#, and you can put HTML straight inside the braces:
@if (Model.InStock)
{
<span class="badge">In stock</span>
}
else if (Model.RestockDate is not null)
{
<span class="badge">Back on @Model.RestockDate.Value.ToShortDateString()</span>
}
else
{
<span class="badge">Sold out</span>
}
@switch is available too, with the same shape as C#.
Loops
@foreach repeats a block of HTML for each item. This is the most used piece of Razor there is:
<ul>
@foreach (var product in Model.Products)
{
<li>@product.Name</li>
}
</ul>
@for and @while work as well:
@for (var i = 1; i <= Model.PageCount; i++)
{
<a asp-action="Index" asp-route-page="@i">@i</a>
}
How Razor knows where HTML starts and ends
Inside a code block or loop, Razor treats a line that starts with an HTML tag as markup, and reads until that tag is closed. That is why you can mix them freely:
@foreach (var product in Model)
{
var cssClass = product.Price > 100 ? "premium" : ""; // C#
<li class="@cssClass">@product.Name</li> // HTML
}
Sometimes you want to print text that is not wrapped in a tag. Use @: for a single line or <text> for several:
@if (Model.Count == 0)
{
@:No products yet.
}
@if (Model.IsOnSale)
{
<text>
On sale now!
Limited time only.
</text>
}
The <text> tag is not sent to the browser. It only marks the lines as content.
Comments
Razor comments never reach the browser, unlike HTML comments:
@* This is invisible in the page source *@
<!-- This is visible in the page source -->
Use Razor comments for notes to other developers. Anything in an HTML comment is public.
Printing a literal @
To show an @ in the page, double it:
<p>Follow us at @@shopapp</p>
Email addresses are a special case. Razor recognises them and leaves them alone, so support@shopapp.com prints correctly without any escaping.
Everything is encoded
Values printed with @ are HTML encoded, which turns < into < and so on. If a value genuinely contains HTML that you trust and want rendered, use Html.Raw:
@Html.Raw(Model.TrustedHtmlFromCms)
Only do this with content you control. Never pass user input to Html.Raw.
Directives at the top of a view
Lines that start with @ followed by a keyword are directives. They set up the view rather than printing anything:
@model Product
@using ShopApp.Services
@inject IPriceFormatter Prices
<h1>@Model.Name</h1>
<p>@Prices.Format(Model.Price)</p>
@modeldeclares the model type.@usingimports a namespace, just like in C#.@injectasks the dependency injection container for a service and gives it a name.
Directives that every view needs, such as @using ShopApp.Models, belong in _ViewImports.cshtml so you write them once.
Functions inside a view
For a tiny helper used only in this view, @functions lets you declare a method:
@functions {
string Stars(int rating) => new string('*', rating);
}
<p>@Stars(Model.Rating)</p>
Keep these rare. Shared helpers belong in C# classes, where they can be tested.
Whitespace
Razor removes the lines that contain only code, so your HTML output stays tidy. It keeps the whitespace inside markup exactly as you wrote it. You rarely need to think about this.
Quick recap
@switches from HTML to C#.@Model.Nameprints a value, and@( ... )marks where a longer expression ends.@{ ... }runs statements without printing. Keep the logic in there short.@if,@foreachand@forwrap HTML directly. Use@:or<text>for text without a tag.@* ... *@is a comment that never reaches the browser.@@prints a literal@. Email addresses need no escaping.- Printed values are HTML encoded.
Html.Rawdisables that, so only use it on content you trust. @model,@usingand@injectset up a view. Put the common ones in_ViewImports.cshtml.
@* Views/Products/Details.cshtml: every everyday piece of Razor syntax in one page *@
@model ShopApp.Models.Product
@using ShopApp.Services
@inject IPriceFormatter Prices
@{
ViewData["Title"] = Model.Name;
var total = Model.Price * Model.Quantity;
var shipping = total > 100 ? "Free shipping" : "Standard shipping";
}
<h1>@Model.Name</h1>
@* Implicit expression, method call and explicit expression *@
<p>Unit price: @Prices.Format(Model.Price)</p>
<p>Total for @Model.Quantity: @(Model.Price * Model.Quantity)</p>
<p>@shipping</p>
@* Condition with HTML inside each branch *@
@if (Model.InStock)
{
<span class="badge bg-success">In stock</span>
}
else if (Model.RestockDate is not null)
{
<span class="badge bg-warning">Back on @Model.RestockDate.Value.ToShortDateString()</span>
}
else
{
<span class="badge bg-secondary">Sold out</span>
}
@* Loop with a C# line and an HTML line side by side *@
<ul>
@foreach (var tag in Model.Tags)
{
var cssClass = tag == "sale" ? "text-danger" : "";
<li class="@cssClass">@tag</li>
}
</ul>
@* Text with no tag *@
@if (Model.Tags.Count == 0)
{
@:No tags for this product.
}
@* Literal @ and an email address *@
<p>Questions? Email support@shopapp.com or message @@shopapp</p>
@* Trusted HTML from your own CMS, never from user input *@
<div class="description">@Html.Raw(Model.DescriptionHtml)</div>
@functions {
string Stars(int rating) => new string('*', rating);
}
<p>Rating: @Stars(Model.Rating)</p>
<a asp-action="Index">Back to list</a>
Was this explanation helpful?
Your feedback helps us improve the content for everyone.
Thank you for your feedback!
We appreciate you helping us improve.
What could we improve? (Optional)
Read aloud
Ready