如果写过 HTML 里嵌 <?php ?> 的页面吧?Razor 干的事差不多,只不过嵌入式用的是 C#。Razor 标记可以塞进 .cshtml(MVC 视图/Razor Pages)或者 .razor(Blazor 组件),写法跟 Vue 的模板语法有几分神似。下面从最基础的开始,一路讲到那些容易被忽视的坑。
1. 怎么输出 HTML
Razor 的默认语言就是 HTML,你写 <p>Hello</p>,它就乖乖输出 <p>Hello</p>。但是想混入 C# 逻辑的时候,就得靠 @ 符号了。
2. @ 符号的用法
@ 是 Razor 的开关------从 HTML 模式切到 C# 模式。
- 输出
@ 本身 :写@@,比如@@Username输出就是@Username。 - 邮件地址里的
@ :Razor 不会碰它,Support@contoso.com照原样输出。 - 隐式表达式 :
@DateTime.Now,直接跟在@后面的 C# 代码。不能有空格(await例外),也不能写泛型------<>会被当成 HTML 标签。 - 显式表达式 :
@(DateTime.Now - TimeSpan.FromDays(7)),括号里头随便写,泛型也行:@(GenericMethod<int>())。
3. SVG 里的 Razor
SVG 的 foreignObject 元素里可以用 Razor 表达式,没什么特别的限制。
4. 表达式编码
字符串表达式默认会被 HTML 编码。@("<span>bold</span>") 输出的是 <span>bold</span> 文本,而不是一个 span 标签。
非要输出原始 HTML,用 @Html.Raw(...)。但注意 :永远别对用户的输入用 Raw,那是 XSS 漏洞直通车。
5. 代码块
用 @{ ... } 把多行 C# 代码包起来,里面的代码不会直接输出。但你可以在代码块里嵌套 HTML:
csharp
@{
var name = "张三";
<p>你好,@name</p>
}
你还可以在代码块里定义本地函数:
csharp
@{
void RenderName(string name) {
<p>@name</p>
}
RenderName("李四");
}
6. 从 C# 切回 HTML
代码块里想回到 HTML 模式,有 3 种办法:
| 方式 | 示例 | 说明 |
|---|---|---|
| 直接写 HTML | <div>内容</div> |
碰到 HTML 标签自动切回 |
<text> 标签 |
<text>纯文本</text> |
输出纯文本,不生成 DOM 元素 |
@: 语法 |
@:这是一行文本 |
把整行切回 HTML |
常见坑 :代码块里多写一个
@就会引发诡异的编译器错误,排查起来很头大。
7. 条件属性呈现
属性值是 null 或 false 时,Razor 会直接省略该属性。比如 class="@false" 最终输出 <div>False</div>(因为 false 不是 null 也不是 false 这个单词,它是布尔值)。
例外 :
data- 属性就算值为null 或false也会保留。
8. 控制结构一览
| 类型 | 语法 |
|---|---|
| 条件 | @if,else if,else,@switch |
| 循环 | @for,@foreach,@while,@do while |
| 复合语句 | @using (Html.BeginForm()) { ... } |
| 异常 | @try ... catch ... finally |
| 锁 | @lock (SomeLock) { ... } |
9. 三种注释
- C# 注释 :
/* ... */和// ...,在服务端处理,不会到客户端。 - HTML 注释 :
<!-- ... -->,会发送到浏览器。 - Razor 注释 :
@* ... *@,服务端直接删除,客户端拿不到。适合隐藏敏感逻辑。
10. 指令大全
指令是 Razor 的「元操作」,控制页面怎么编译、怎么跑、从哪拿数据。
| 指令 | 干的事 | 用在哪儿 |
|---|---|---|
@attribute |
往生成的类上加属性,比如[Authorize] |
视图/页面/组件 |
@code |
加 C# 成员(属性、方法) | .razor组件 |
@functions |
同上,但用于.cshtml |
.cshtml视图 |
@implements |
实现接口 | 所有文件 |
@inherits |
指定自定义基类 | 所有文件 |
@inject |
依赖注入 | 所有文件 |
@layout |
指定布局 | .razor组件 |
@model |
指定强类型模型 | .cshtml |
@namespace |
设置命名空间 | 导入文件(_ViewImports.cshtml) |
@page |
声明为可路由的页面/组件 | .cshtml/.razor |
@preservewhitespace |
控制是否保留多余空白 | .razor |
@rendermode |
设置 Blazor 渲染模式 | .razor |
@section |
定义布局节 | .cshtml |
@typeparam |
泛型类型参数 | .razor |
@using |
添加using指令 |
所有文件 |
11. 指令属性
这些属性直接用在 HTML 标签上:
@attributes:批量展开任意属性(仅限组件)@bind、@bind:culture:双向数据绑定 + 区域性格式@formname:防止表单冲突@on{event}、@on{event}:preventDefault、@on{event}:stopPropagation:事件处理全家桶@key:保留元素/组件身份(Diff 算法用)@ref:获取组件实例引用
12. 模板化 Razor 委托
可以用 @<tag>...</tag> 定义一段 UI 模板,赋值给委托变量:
csharp
@{
Func<dynamic, object> itemTemplate = @<li>@item</li>;
}
<ul>@itemTemplate("A")@itemTemplate("B")</ul>
也可以当参数传给方法------比如定义一个 Repeat 方法,接收模板委托做内联渲染。
13. 标记帮助程序指令
@addTagHelper:注册标记帮助程序@removeTagHelper:移除已注册的@tagHelperPrefix:设置前缀(比如<vc:...>)
14. 保留关键字
有些词 Razor 自己用了,你不能直接拿来当变量名。
Razor 关键字 (需用 @(keyword) 转义):page, namespace, functions, inherits, model, section, helper(不支持了但保留)
C# Razor 关键字 (需用 @(@keyword) 双转义):case, do, default, for, foreach, if, else, lock, switch, try, catch, finally, using, while
未使用的保留关键字 :class
15. 调试小技巧:查看编译器生成的 C# 类
在 .csproj 里加一行:
csharp
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>
编译后在 obj/Debug/net9.0/Razor/ 目录下找 .g.cshtml.cs 文件,能看到 Razor 把你的标记翻译成了什么 C# 代码。排查绑定错误时特别好用。
16. 视图查找与大小写
- Windows 文件系统不区分大小写,Linux/macOS 区分。但预编译视图不区分。
- 建议统一用小写命名,跨平台迁移时不踩坑。
17. 默认导入
_ViewImports.cshtml 默认帮你 using 了这些命名空间,开箱即用:
csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
一点背景:Razor 最早出现在 ASP.NET MVC 3(2011 年),取代了古老的 Web Forms 视图引擎。到 ASP.NET Core 时代,它不仅是 MVC 的视图引擎,还成了 Blazor 组件的基础。虽然本文描述的某些底层机制在 ASP.NET Core 3.0 后有所调整,但核心语法几乎没有变过。