Razor Syntax — C# in HTML Templates

Razor is ASP.NET Core’s templating language for generating HTML from C# code. It is not a separate language but an extension of HTML — you write normal HTML and sprinkle in C# expressions and code blocks using the @ prefix. Razor views are compiled into C# classes at startup (or publish time), making them fast and type-safe. The key design principle: Razor HTML-encodes all output by default, preventing cross-site scripting (XSS) attacks automatically — you have to explicitly opt out with @Html.Raw() when you need unencoded output.

Core Razor Syntax

@* ── Razor file: Views/Posts/Details.cshtml ───────────────────────────── *@
@model PostDetailsViewModel   @* declares the strongly-typed model *@

@* ── Expressions — @value outputs the value HTML-encoded ─────────────── *@
<h1>@Model.Title</h1>                    @* outputs title, HTML-encoded *@
<p>Published: @Model.PublishedAt:D</p>  @* format specifier *@
<p>Views: @(Model.ViewCount + 1)</p>    @* expression with operators — needs parens *@
<p>@Model.Author.Name</p>               @* dot navigation *@

@* ── Code blocks — arbitrary C# ──────────────────────────────────────── *@
@{
    var readTime = Math.Ceiling(Model.Body.Split(' ').Length / 200.0);
    var isPopular = Model.ViewCount > 1000;
    ViewBag.Title = Model.Title;   @* set ViewBag inside code block *@
}

<p>~@readTime min read @(isPopular ? "⭐ Popular" : "")</p>

@* ── Conditional output ───────────────────────────────────────────────── *@
@if (Model.IsPublished)
{
    <span class="badge bg-success">Published</span>
}
else
{
    <span class="badge bg-warning">Draft</span>
}

@* ── Loops ───────────────────────────────────────────────────────────── *@
<ul>
@foreach (var tag in Model.Tags)
{
    <li><a href="/posts/tag/@tag.Slug">@tag.Name</a></li>
}
</ul>

@* ── Inline literal text inside code block: @: ───────────────────────── *@
@for (int i = 0; i < 3; i++)
{
    @: Item number @i     @* outputs literal text mixed with expression *@
    <br />
}

@* ── Unencoded output — use ONLY for trusted HTML ─────────────────────── *@
@Html.Raw(Model.BodyHtml)   @* outputs HTML without encoding — XSS risk if untrusted! *@
Note: Every @expression in Razor is HTML-encoded before output — <, >, &, and " are converted to their HTML entities. If Model.Title is <script>alert(1)</script>, Razor outputs &lt;script&gt;alert(1)&lt;/script&gt; — harmless text, not executable script. This automatic encoding is the primary XSS defence in Razor views. Only use @Html.Raw() when you have generated or sanitised the HTML yourself — never for user-provided content.
Tip: Prefer the ternary operator and null-coalescing operator inline rather than full @if/@else blocks for simple conditional output. <span>@(Model.IsPublished ? "Live" : "Draft")</span> is more readable than a four-line if/else block. For repeated conditional logic, create a C# helper method in a @functions block or in a separate static helper class imported via @using. Keep the view template focused on presentation, not logic.
Warning: Never use @Html.Raw() with user-provided content. If a user enters <script>document.cookie</script> and you display it with @Html.Raw(userInput), the script executes in every visitor’s browser — a stored XSS attack. Always use plain @userInput for user content. Only use Html.Raw() for pre-sanitised HTML generated by trusted server-side processes (a Markdown-to-HTML converter with a sanitisation step, a CMS content field validated on input).

_ViewImports.cshtml — Global Directives

@* Views/_ViewImports.cshtml — applies to ALL views in this folder and subfolders *@
@using BlogApp.Web.Models
@using BlogApp.Web.ViewModels
@using BlogApp.Application.DTOs
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers   @* enables all built-in Tag Helpers *@
@addTagHelper *, BlogApp.Web                           @* enables any custom Tag Helpers *@

@* ── Without _ViewImports, every view would need: ─────────────────────── *@
@using BlogApp.Web.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@* ... repeated in every single .cshtml file *@

Common Mistakes

Mistake 1 — Using @Html.Raw() with user content (XSS vulnerability)

❌ Wrong — executes injected scripts in visitors’ browsers:

@Html.Raw(Model.UserComment)   @* user comment could contain <script> — XSS! *@

✅ Correct — use plain @Model.UserComment which HTML-encodes automatically.

Mistake 2 — Forgetting parentheses for complex expressions (parse error)

❌ Wrong — Razor parses the + as part of the expression:

<p>Total: @count + 1</p>   @* renders "5 + 1", not "6" *@

✅ Correct — wrap arithmetic in parentheses: @(count + 1).

🧠 Test Yourself

A user submits a comment containing <b>bold text</b>. The view renders it with @Model.Comment. What appears in the browser?