EthicsComputerCourses
Join training +91 90532 10052

Razor Syntax (cshtml)

ASP.NET Core · Lesson 16 of 29 Intermediate 8 min read Updated

Razor is the template language ASP.NET Core uses to build HTML on the server. A Razor file has the extension .cshtml and is mostly ordinary HTML, with C# mixed in wherever the page needs data: a patient's name, a loop over today's appointments, a message that appears only after 8 pm. Razor Pages, MVC views and Blazor components all use it.

In this lesson you will learn how Razor switches between HTML and C#, how it protects you from script injection by encoding output, the directives at the top of a file, and how layouts, sections, partials and tag helpers keep pages consistent.

The @ symbol

The @ character switches from HTML to C#. Razor then works out by itself where the C# ends and HTML starts again.

Razor
@page
@{
    var patients = new[] { "Aarav", "Priya", "Kabir" };
    int fee = 500;
    bool eveningOpen = DateTime.Now.Hour < 20;
}
<h2>Today's queue (@patients.Length patients)</h2>
<ol>
    @foreach (var name in patients)
    {
        <li>@name</li>
    }
</ol>
<p>Consultation fee: ₹@fee, follow-up: ₹@(fee / 2)</p>
@if (eveningOpen)
{
    <p>Evening OPD is open until 8 pm.</p>
}
else
{
    <p>Closed for today. Please book online for tomorrow.</p>
}

Before 8 pm the browser receives this HTML (blank lines removed):

HTML
<h2>Today's queue (3 patients)</h2>
<ol>
        <li>Aarav</li>
        <li>Priya</li>
        <li>Kabir</li>
</ol>
<p>Consultation fee: ₹500, follow-up: ₹250</p>
<p>Evening OPD is open until 8 pm.</p>

The forms of @ you just used:

SyntaxNameExample
@nameImplicit expression@patients.Length, @Model.Name
@( ... )Explicit expression@(fee / 2), @(a + b), generic calls like @(Get<int>())
@{ ... }Code blockDeclare variables, run statements; nothing is output by itself
@if, @foreach, @for, @switch, @whileControl structuresHTML inside the braces is output when the code runs
@* ... *@Razor commentRemoved completely; never sent to the browser

An implicit expression stops at a space, so @fee / 2 would print 500 / 2. Use the explicit form @(fee / 2) for calculations. Razor also recognises email addresses: help@shanticlinic.in is printed as text, not treated as code. To print a literal @ before a word, write @@.

Text inside code blocks

Inside a code block, Razor treats a line that starts with an HTML tag as markup. Plain text without a tag needs a marker:

Razor
@foreach (var slot in new[] { "10:00", "10:15", "10:30" })
{
    @:Slot @slot is free.
    <text>Book now.</text>
}

@: outputs the rest of the line as text, and <text>...</text> outputs its content without adding a real HTML element.

Automatic HTML encoding

Every @ expression is HTML-encoded before it is written. Characters that mean something in HTML, such as <, >, & and quotes, become safe entities. This is your main protection against cross-site scripting (XSS), where a user submits a script that would otherwise run in other users' browsers.

Razor
@{
    string review = "<script>alert('hacked')</script> Great doctor!";
    string city = "पुणे";
}
<p>@review</p>
<p>@city</p>
HTML
<p>&lt;script&gt;alert(&#x27;hacked&#x27;)&lt;/script&gt; Great doctor!</p>
<p>&#x92A;&#x941;&#x923;&#x947;</p>

The script arrives as harmless text. The Hindi city name is also encoded, as numeric character references; browsers display it correctly as "पुणे", but the page source is hard to read and slightly larger. By default the encoder leaves only basic Latin characters unencoded. To keep Devanagari as it is, register a wider encoder in Program.cs:

C#
using System.Text.Encodings.Web;
using System.Text.Unicode;

builder.Services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.Devanagari));

Text you type directly in the .cshtml markup, such as the ₹ sign in the first example, is not encoded; only @ expressions are.

Directives

Lines at the top of a file that start with @ and a keyword are directives. They configure the whole file:

DirectivePurpose
@pageMakes the file a Razor Page with its own URL (Razor Pages only, must be the first line)
@model TypeDeclares the type of Model for the view or page
@using NamespaceAdds a using for this file
@inject IService NameInjects a service from DI into a property called Name
@section Name { ... }Defines content that the layout places in a named spot
@functions { ... }Adds C# methods and fields to the generated class
@addTagHelper *, AssemblyEnables the tag helpers from an assembly

Layouts, sections and _ViewStart

Every page on a site shares a header, navigation and footer. A layout holds that shared HTML, and each page supplies only its own part. Pages/Shared/_Layout.cshtml (or Views/Shared/_Layout.cshtml in MVC):

Razor
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>@ViewData["Title"] - Shanti Clinic</title>
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</head>
<body>
    <header><a asp-page="/Index">Shanti Clinic, Pune</a></header>
    <main>@RenderBody()</main>
    <footer>Open Mon-Sat, 10:00-13:00</footer>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

@RenderBody() is where the page's own content goes. RenderSectionAsync("Scripts", required: false) is an optional slot that a page can fill:

Razor
@page
@{
    ViewData["Title"] = "Book an appointment";
}
<h1>Book an appointment</h1>
<p>Choose a doctor and a free slot.</p>

@section Scripts {
    <script src="~/js/booking.js"></script>
}

Two special files apply to every page in their folder and below:

  • _ViewStart.cshtml runs before each page; the template's version contains @{ Layout = "_Layout"; }, so you never repeat it.
  • _ViewImports.cshtml holds shared directives, such as @using ShantiClinic.Models and @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers.

Partials and tag helpers

A partial view is a reusable piece of markup, such as a doctor card used on several pages. Create Pages/Shared/_DoctorCard.cshtml with @model Doctor, then render it with <partial name="_DoctorCard" model="doctor" />.

Tag helpers are attributes and elements, starting with asp-, that run C# on the server to produce correct HTML:

  • <a asp-page="/Doctors/Details" asp-route-id="3"> builds the link /Doctors/Details/3 (or ?id=3) from routing.
  • <input asp-for="Input.PatientName" /> sets the name, id, value, type and validation attributes from the model property.
  • <span asp-validation-for="Input.PatientName"></span> shows that field's validation message.
  • <link asp-append-version="true"> adds a version to static file URLs.
  • <environment include="Development">...</environment> outputs its content only in that environment.

Tag helpers look like normal HTML, so designers can still read the files, and they keep URLs and form field names in sync with your C# code.

Common mistakes

  • @fee * 2 instead of @(fee * 2). The implicit form stops at the space and prints the rest as text.
  • Using Html.Raw on user data. It disables encoding and opens an XSS hole.
  • Forgetting @addTagHelper in _ViewImports.cshtml. asp- attributes are then sent to the browser unchanged and links are broken.
  • Heavy logic in views. Calculations and database calls belong in the page model or controller; views should only display data.
  • Putting @page anywhere but the first line. The file then stops being a routable page.

Key points

  • @ switches to C#: implicit expressions (@name), explicit expressions (@(a + b)), code blocks (@{ }) and control structures (@if, @foreach).
  • All @ output is HTML-encoded automatically; @Html.Raw turns this off and must never receive user input.
  • Directives such as @page, @model, @inject and @section configure a file.
  • Layouts use @RenderBody() and sections; _ViewStart.cshtml sets the layout and _ViewImports.cshtml shares directives.
  • Partials reuse markup, and asp- tag helpers generate links, form fields and validation messages from your C# model.

Exercise

Write a Razor Page Pages/Fees.cshtml for a coaching centre in Lucknow. In a code block, create an array of (string Course, int Fee) tuples: ("Maths", 1200), ("Physics", 1100), ("Chemistry", 1000). Show them in an HTML table with a header row, show the total fee below the table, and show the message "Sibling discount: 10%" only when the total is more than ₹3,000. Set the page title to "Course Fees".

Show solution
Razor
@page
@{
    ViewData["Title"] = "Course Fees";
    var courses = new (string Course, int Fee)[]
    {
        ("Maths", 1200), ("Physics", 1100), ("Chemistry", 1000)
    };
    int total = courses.Sum(c => c.Fee);
}
<h1>Course Fees</h1>
<table>
    <tr><th>Course</th><th>Fee</th></tr>
    @foreach (var c in courses)
    {
        <tr><td>@c.Course</td><td>₹@c.Fee</td></tr>
    }
</table>
<p>Total: ₹@total</p>
@if (total > 3000)
{
    <p>Sibling discount: 10%</p>
}

The total is 3,300, so the discount message appears. courses.Sum works because System.Linq is among the implicit usings, and ViewData["Title"] is read by the layout's <title> element.

Quick Quiz

1. What does @(price * 2) do that @price * 2 does not?

2. A user's review contains <script>. What does <p>@review</p> output?

3. Where does a page's own content appear inside a layout?

4. Which file usually contains @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers?

Learn ASP.NET Core with a mentor

Free lessons get you started. Our Programming & Software Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call