# Razor Syntax and Tag Helpers

Mix C# into HTML with Razor's @ expressions, code blocks, if and foreach, and let tag helpers such as asp-action and asp-route-id write your links.

Journeyman · ASP.NET Core · Razor · C# · Updated November 3, 2026

## After this lesson you can

- Mix C# into HTML with Razor's @ expressions, @{ } blocks, @if and @foreach
- Build links with tag helpers such as asp-controller, asp-action and asp-route-id

## Key takeaways

- `@` shows a value, and a calculation needs parentheses: `@(Model.UnitPrice * 2)`.
- `@{ }` runs C# without showing anything; `@if` and `@foreach` work like C#'s, with HTML inside their braces.
- Razor HTML-encodes what `@` shows, so HTML a user typed appears as text instead of running.
- Build links with tag helpers such as `asp-controller`, `asp-action` and `asp-route-id`, not hand-typed addresses, so they follow the route.

**Razor** is the syntax of `.cshtml` files. A view is mostly HTML, and the `@` sign switches to C# wherever you need it. Razor works out where the C# ends by itself, so there's little to type.

All the examples on this page are from one view whose model is Northwind product 8, Northwoods Cranberry Sauce: $40.00, with 6 in stock.

## @ shows a value

`@` followed by a name shows that value in the page:

```cshtml
<p>@Model.ProductName</p>
```

```html
<p>Northwoods Cranberry Sauce</p>
```

Razor reads the C# up to the first character that can't be part of a name, such as a space or `<`. So a calculation needs parentheses, **`@( )`**, or Razor stops too soon:

```cshtml
<p>@Model.UnitPrice * 2</p>
<p>@(Model.UnitPrice * 2)</p>
```

```html
<p>40.0000 * 2</p>
<p>80.0000</p>
```

The first line showed the price, then the text ` * 2`. And `40.0000`? Northwind's prices are SQL Server `money`, which keeps four decimal places. Format it as money with `ToString("C")`, as the product views do.

## @{ } runs code

A **code block**, `@{ ... }`, runs C# without showing anything: declare variables, work things out, set `ViewData`. Every view you've seen starts with one:

```cshtml
@{
    ViewData["Title"] = Model.ProductName;
    decimal priceWithTax = Model.UnitPrice!.Value * 1.08m;
}

<p>With tax: @priceWithTax.ToString("C")</p>
```

```html
<p>With tax: $43.20</p>
```

## @if and @foreach

C#'s `if`, `foreach`, `for` and `switch` work with an `@` in front. Inside their braces, you're back in HTML:

```cshtml
@if (Model.UnitsInStock < 20)
{
    <p>Only @Model.UnitsInStock left!</p>
}

@for (int i = 1; i <= 3; i++)
{
    <span>@i</span>
}
```

```html
<p>Only 6 left!</p>
<span>1</span>
<span>2</span>
<span>3</span>
```

`@foreach` is the one you'll use most: one table row, list item or card per item in the model, as in the products table in *Passing a Model to a View*.

## Razor encodes what it shows

Text shown with `@` is **HTML-encoded**: characters that mean something in HTML, such as `<`, `>` and `'`, are turned into codes the browser shows as plain characters.

```cshtml
@{
    string warning = "<b>Low stock</b>";
}
<p>@warning</p>
```

```html
<p>&lt;b&gt;Low stock&lt;/b&gt;</p>
```

The browser shows `<b>Low stock</b>` as text, not bold. That's a safety feature: if a user types HTML or JavaScript into a form, your pages show it as text instead of running it. (It's also why the page for product 7 has `Uncle Bob&#x27;s` in its source: `&#x27;` is the code for `'`.)

## A few more

| You write | You get |
|---|---|
| `@* a note *@` | A Razor comment: it never reaches the browser |
| `sales@northwind.com` | An email address stays text: Razor sees the letters before the `@` |
| `@@northwind` | A literal `@`, as in `@northwind` |

## Tag helpers write your links

You could type links by hand: `<a href="/Products/Details/8">`. But if a route ever changes, every hand-written address breaks. **Tag helpers** are `asp-` attributes that ASP.NET Core turns into the right HTML when the page is built:

```cshtml
<a asp-controller="Products" asp-action="Details" asp-route-id="@Model.ProductId">Details</a>
<a asp-action="Index">All products</a>
<a asp-controller="Home" asp-action="Index">Home</a>
<a asp-action="Search" asp-route-name="sauce">Sauces</a>
```

```html
<a href="/Products/Details/8">Details</a>
<a href="/Products">All products</a>
<a href="/">Home</a>
<a href="/Products/Search?name=sauce">Sauces</a>
```

| Attribute | Means |
|---|---|
| `asp-controller` | Which controller. Leave it out for the current view's controller. |
| `asp-action` | Which action |
| `asp-route-id` | The route's `id` part |
| `asp-route-`*anything else* | A query-string value: `asp-route-name="sauce"` adds `?name=sauce` |

Notice the tag helpers know the route: they leave out `Index` and `Home` where the defaults cover them.

Tag helpers work because of one line in `Views/_ViewImports.cshtml`:

```cshtml
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
```

Now link the products list to the details pages. In `Views/Products/Index.cshtml`, change the name cell to:

```cshtml
<td><a asp-action="Details" asp-route-id="@product.ProductId">@product.ProductName</a></td>
```

Other tag helpers do other jobs. `asp-append-version` in the layout adds a version to CSS and JavaScript addresses so browsers fetch fresh copies, and the form tag helpers, `asp-for` above all, are the subject of *MVC Forms*.

## Common problems

| What you see | What to do |
|---|---|
| The page shows `* 2` or `.ToString("C")` as text | Razor stopped reading C# too soon. Wrap the expression in `@( )`. |
| A link leads to a 404 page | The tag helper writes an address for any name, even a misspelled one. Check the spelling in `asp-action` and `asp-controller`. |
| `asp-action` shows up in the page's HTML | Tag helpers are off: `_ViewImports.cshtml` is missing its `@addTagHelper` line. |

## Check yourself

2 questions to try on the lesson page.

## So what

`@` for values, `@{ }` for code, `@if` and `@foreach` for logic, and `asp-` attributes for links: that's most of Razor. With it, one view turns any product, or a list of seventy-seven, into a page.

## Key terms

- Razor
- Razor Expression
- Code Block
- HTML Encoding
- Tag Helper
- asp-action

## Cheat sheets

- [Razor Syntax and Tag Helpers](https://www.ask-codey.com/cheat-sheets/razor-views-razor-syntax-and-tag-helpers-cheat-sheet)

Source: https://www.ask-codey.com/lessons/razor-views-razor-syntax-and-tag-helpers
