ASP.NET Core 的 Razor 语法参考Razor syntax reference for ASP.NET Core

本文内容

作者: Rick AndersonTaylor MullenDan Vicarel

Razor 是一种标记语法,用于将基于服务器的代码嵌入网页中。Razor 语法由 Razor 标记、C# 和 HTML 组成。包含 Razor 的文件通常具有 .cshtml 文件扩展名。Razor 组件文件 (.razor) 中也可以找到 Razor。

呈现 HTMLRendering HTML

默认 Razor 语言为 HTML。从 Razor 标记呈现 HTML 与从 HTML 文件呈现 HTML 并没有什么不同。服务器会按原样呈现 .cshtml Razor 文件中的 HTML 标记。

Razor 语法Razor syntax

Razor 支持 C#,并使用 @ 符号从 HTML 转换为 C#。Razor 计算 C# 表达式,并将它们呈现在 HTML 输出中。

@ 符号后跟 Razor 保留关键字时,它会转换为 Razor 特定标记。否则会转换为纯 C#。

若要对 Razor 标记中的 @ 符号进行转义,请使用另一个 @ 符号:

  1. <p>@@Username</p>

该代码在 HTML 中使用单个 @ 符号呈现:

  1. <p>@Username</p>

包含电子邮件地址的 HTML 属性和内容不将 @ 符号视为转换字符。Razor 分析不会处理以下示例中的电子邮件地址:

  1. <a href="mailto:Support@contoso.com">Support@contoso.com</a>

隐式 Razor 表达式Implicit Razor expressions

隐式 Razor 表达式以 @ 开头,后跟 C# 代码:

  1. <p>@DateTime.Now</p>
  2. <p>@DateTime.IsLeapYear(2016)</p>

隐式表达式不能包含空格,但 C# await 关键字除外。如果该 C# 语句具有明确的结束标记,则可以混用空格:

  1. <p>@await DoSomething("hello", "world")</p>

隐式表达式不能包含 C# 泛型,因为括号 (<>) 内的字符会被解释为 HTML 标记。以下代码效:

  1. <p>@GenericMethod<int>()</p>

上述代码生成与以下错误之一类似的编译器错误:

  • "int" 元素未结束。所有元素都必须自结束或具有匹配的结束标记。
  • 无法将方法组 "GenericMethod" 转换为非委托类型 "object"。是否希望调用此方法?`

泛型方法调用必须包装在显式 Razor 表达式Razor 代码块中。

显式 Razor 表达式Explicit Razor expressions

显式 Razor 表达式由 @ 符号和平衡圆括号组成。若要呈现上一周的时间,可使用以下 Razor 标记:

  1. <p>Last week this time: @(DateTime.Now - TimeSpan.FromDays(7))</p>

将计算 @() 括号中的所有内容,并将其呈现到输出中。

前面部分中所述的隐式表达式通常不能包含空格。在下面的代码中,不会从当前时间减去一周:

  1. <p>Last week: @DateTime.Now - TimeSpan.FromDays(7)</p>

该代码呈现以下 HTML:

  1. <p>Last week: 7/7/2016 4:39:52 PM - TimeSpan.FromDays(7)</p>

可以使用显式表达式将文本与表达式结果串联起来:

  1. @{
  2. var joe = new Person("Joe", 33);
  3. }
  4. <p>Age@(joe.Age)</p>

如果不使用显式表达式,<p>Age@joe.Age</p> 会被视为电子邮件地址,因此会呈现 <p>Age@joe.Age</p>如果编写为显式表达式,则呈现 <p>Age33</p>

显式表达式可用于从 .cshtml 文件中的泛型方法呈现输出。以下标记显示了如何更正之前出现的由 C# 泛型的括号引起的错误。此代码以显式表达式的形式编写:

  1. <p>@(GenericMethod<int>())</p>

表达式编码Expression encoding

计算结果为字符串的 C# 表达式采用 HTML 编码。计算结果为 IHtmlContent 的 C# 表达式直接通过 IHtmlContent.WriteTo 呈现。计算结果不为 IHtmlContent 的 C# 表达式通过 ToString 转换为字符串,并在呈现前进行编码。

  1. @("<span>Hello World</span>")

该代码呈现以下 HTML:

  1. &lt;span&gt;Hello World&lt;/span&gt;

该 HTML 在浏览器中显示为:

  1. <span>Hello World</span>

HtmlHelper.Raw 输出不进行编码,但呈现为 HTML 标记。

警告

对未经审查的用户输入使用 HtmlHelper.Raw 会带来安全风险。用户输入可能包含恶意的 JavaScript 或其他攻击。审查用户输入比较困难。应避免对用户输入使用 HtmlHelper.Raw

  1. @Html.Raw("<span>Hello World</span>")

该代码呈现以下 HTML:

  1. <span>Hello World</span>

Razor 代码块Razor code blocks

Razor 代码块以 @ 开头,并括在 {} 中。代码块内的 C# 代码不会呈现,这点与表达式不同。一个视图中的代码块和表达式共享相同的作用域并按顺序进行定义:

  1. @{
  2. var quote = "The future depends on what you do today. - Mahatma Gandhi";
  3. }
  4. <p>@quote</p>
  5. @{
  6. quote = "Hate cannot drive out hate, only love can do that. - Martin Luther King, Jr.";
  7. }
  8. <p>@quote</p>

该代码呈现以下 HTML:

  1. <p>The future depends on what you do today. - Mahatma Gandhi</p>
  2. <p>Hate cannot drive out hate, only love can do that. - Martin Luther King, Jr.</p>

在代码块中,使用标记将本地函数声明为用作模板化方法:

  1. @{
  2. void RenderName(string name)
  3. {
  4. <p>Name: <strong>@name</strong></p>
  5. }
  6. RenderName("Mahatma Gandhi");
  7. RenderName("Martin Luther King, Jr.");
  8. }

该代码呈现以下 HTML:

  1. <p>Name: <strong>Mahatma Gandhi</strong></p>
  2. <p>Name: <strong>Martin Luther King, Jr.</strong></p>

隐式转换Implicit transitions

代码块中的默认语言为 C#,不过,Razor 页面可以转换回 HTML:

  1. @{
  2. var inCSharp = true;
  3. <p>Now in HTML, was in C# @inCSharp</p>
  4. }

带分隔符的显式转换Explicit delimited transition

若要定义应呈现 HTML 的代码块子节,请使用 Razor <text> 标记将要呈现的字符括起来:

  1. @for (var i = 0; i < people.Length; i++)
  2. {
  3. var person = people[i];
  4. <text>Name: @person.Name</text>
  5. }

使用此方法可呈现未被 HTML 标记括起来的 HTML。如果没有 HTML 或 Razor 标记,会发生 Razor 运行时错误。

<text> 标记可用于在呈现内容时控制空格:

  • 仅呈现 <text> 标记之间的内容。
  • <text> 标记之前或之后的空格不会显示在 HTML 输出中。

显式行转换Explicit line transition

要在代码块内以 HTML 形式呈现整个行的其余内容,请使用 @: 语法:

  1. @for (var i = 0; i < people.Length; i++)
  2. {
  3. var person = people[i];
  4. @:Name: @person.Name
  5. }

如果代码中没有 @:,会生成 Razor 运行时错误。

Razor 文件中多余的 @ 字符可能会导致代码块中后面的语句发生编译器错误。这些编译器错误可能难以理解,因为实际错误发生在报告的错误之前。将多个隐式/显式表达式合并到单个代码块以后,经常会发生此错误。

控制结构Control structures

控制结构是对代码块的扩展。代码块的各个方面(转换为标记、内联 C#)同样适用于以下结构:

条件语句 @、else if、else 和 @switchConditionals @if, else if, else, and @switch

@if 控制何时运行代码:

  1. @if (value % 2 == 0)
  2. {
  3. <p>The value was even.</p>
  4. }

elseelse if 不需要 @ 符号:

  1. @if (value % 2 == 0)
  2. {
  3. <p>The value was even.</p>
  4. }
  5. else if (value >= 1337)
  6. {
  7. <p>The value is large.</p>
  8. }
  9. else
  10. {
  11. <p>The value is odd and small.</p>
  12. }

以下标记展示如何使用 switch 语句:

  1. @switch (value)
  2. {
  3. case 1:
  4. <p>The value is 1!</p>
  5. break;
  6. case 1337:
  7. <p>Your number is 1337!</p>
  8. break;
  9. default:
  10. <p>Your number wasn't 1 or 1337.</p>
  11. break;
  12. }

循环语句 @for、@foreach、@while 和 @dowhileLooping @for, @foreach, @while, and @do while

可以使用循环控制语句呈现模板化 HTML。若要呈现一组人员:

  1. @{
  2. var people = new Person[]
  3. {
  4. new Person("Weston", 33),
  5. new Person("Johnathon", 41),
  6. ...
  7. };
  8. }

支持以下循环语句:

@for

  1. @for (var i = 0; i < people.Length; i++)
  2. {
  3. var person = people[i];
  4. <p>Name: @person.Name</p>
  5. <p>Age: @person.Age</p>
  6. }

@foreach

  1. @foreach (var person in people)
  2. {
  3. <p>Name: @person.Name</p>
  4. <p>Age: @person.Age</p>
  5. }

@while

  1. @{ var i = 0; }
  2. @while (i < people.Length)
  3. {
  4. var person = people[i];
  5. <p>Name: @person.Name</p>
  6. <p>Age: @person.Age</p>
  7. i++;
  8. }

@do while

  1. @{ var i = 0; }
  2. @do
  3. {
  4. var person = people[i];
  5. <p>Name: @person.Name</p>
  6. <p>Age: @person.Age</p>
  7. i++;
  8. } while (i < people.Length);

复合语句 @usingCompound @using

在 C# 中,using 语句用于确保释放对象。在 Razor 中,可使用相同的机制来创建包含附加内容的 HTML 帮助程序。在下面的代码中,HTML 帮助程序使用 <form> 语句呈现 @using 标记:

  1. @using (Html.BeginForm())
  2. {
  3. <div>
  4. Email: <input type="email" id="Email" value="">
  5. <button>Register</button>
  6. </div>
  7. }

@try、catch、finally@try, catch, finally

异常处理与 C# 类似:

  1. @try
  2. {
  3. throw new InvalidOperationException("You did something invalid.");
  4. }
  5. catch (Exception ex)
  6. {
  7. <p>The exception message: @ex.Message</p>
  8. }
  9. finally
  10. {
  11. <p>The finally statement.</p>
  12. }

@lock@lock

Razor 可以使用 lock 语句来保护关键节:

  1. @lock (SomeLock)
  2. {
  3. // Do critical section work
  4. }

注释Comments

Razor 支持 C# 和 HTML 注释:

  1. @{
  2. /* C# comment */
  3. // Another C# comment
  4. }
  5. <!-- HTML comment -->

该代码呈现以下 HTML:

  1. <!-- HTML comment -->

在呈现网页之前,服务器会删除 Razor 注释。Razor 使用 @ @ 来分隔注释。以下代码已被注释禁止,因此服务器不呈现任何标记:

  1. @*
  2. @{
  3. /* C# comment */
  4. // Another C# comment
  5. }
  6. <!-- HTML comment -->
  7. *@

指令Directives

Razor 指令由隐式表达式表示:@ 符号后跟保留关键字。指令通常用于更改视图分析方式或启用不同的功能。

通过了解 Razor 如何为视图生成代码,更易理解指令的工作原理。

  1. @{
  2. var quote = "Getting old ain't for wimps! - Anonymous";
  3. }
  4. <div>Quote of the Day: @quote</div>

该代码生成与下面类似的类:

  1. public class _Views_Something_cshtml : RazorPage<dynamic>
  2. {
  3. public override async Task ExecuteAsync()
  4. {
  5. var output = "Getting old ain't for wimps! - Anonymous";
  6. WriteLiteral("/r/n<div>Quote of the Day: ");
  7. Write(output);
  8. WriteLiteral("</div>");
  9. }
  10. }

本文后面的检查为视图生成的 Razor C# 类部分说明了如何查看此生成的类。

@attribute@attribute

@attribute 指令将给定的属性添加到生成的页或视图的类中。以下示例添加 [Authorize] 属性:

  1. @attribute [Authorize]

@code@code

此方案仅适用于 Razor 组件 (.razor)。

@code 块允许 Razor 组件将 C# 成员(字段、属性和方法)添加到组件:

  1. @code {
  2. // C# members (fields, properties, and methods)
  3. }

对于 Razor 组件,@code@functions 的别名,并且优先于 @functions 使用。允许多个 @code 块。

@functions@functions

@functions 指令允许将 C# 成员(字段、属性和方法)添加到生成的类中:

  1. @functions {
  2. // C# members (fields, properties, and methods)
  3. }

Razor 组件中,请使用 @code 而不是 @functions 来添加 C# 成员。

例如:

  1. @functions {
  2. public string GetHello()
  3. {
  4. return "Hello";
  5. }
  6. }
  7. <div>From method: @GetHello()</div>

该代码生成以下 HTML 标记:

  1. <div>From method: Hello</div>

以下代码是生成的 Razor C# 类:

  1. using System.Threading.Tasks;
  2. using Microsoft.AspNetCore.Mvc.Razor;
  3. public class _Views_Home_Test_cshtml : RazorPage<dynamic>
  4. {
  5. // Functions placed between here
  6. public string GetHello()
  7. {
  8. return "Hello";
  9. }
  10. // And here.
  11. #pragma warning disable 1998
  12. public override async Task ExecuteAsync()
  13. {
  14. WriteLiteral("\r\n<div>From method: ");
  15. Write(GetHello());
  16. WriteLiteral("</div>\r\n");
  17. }
  18. #pragma warning restore 1998

@functions 方法有标记时,会用作模板化方法:

  1. @{
  2. RenderName("Mahatma Gandhi");
  3. RenderName("Martin Luther King, Jr.");
  4. }
  5. @functions {
  6. private void RenderName(string name)
  7. {
  8. <p>Name: <strong>@name</strong></p>
  9. }
  10. }

该代码呈现以下 HTML:

  1. <p>Name: <strong>Mahatma Gandhi</strong></p>
  2. <p>Name: <strong>Martin Luther King, Jr.</strong></p>

@implements@implements

@implements 指令为生成的类实现接口。

以下示例实现 System.IDisposable,以便可以调用 Dispose 方法:

  1. @implements IDisposable
  2. <h1>Example</h1>
  3. @functions {
  4. private bool _isDisposed;
  5. ...
  6. public void Dispose() => _isDisposed = true;
  7. }

@inherits@inherits

@inherits 指令对视图继承的类提供完全控制:

  1. @inherits TypeNameOfClassToInheritFrom

下面的代码是一种自定义 Razor 页面类型:

  1. using Microsoft.AspNetCore.Mvc.Razor;
  2. public abstract class CustomRazorPage<TModel> : RazorPage<TModel>
  3. {
  4. public string CustomText { get; } =
  5. "Gardyloo! - A Scottish warning yelled from a window before dumping" +
  6. "a slop bucket on the street below.";
  7. }

CustomText 显示在视图中:

  1. @inherits CustomRazorPage<TModel>
  2. <div>Custom text: @CustomText</div>

该代码呈现以下 HTML:

  1. <div>
  2. Custom text: Gardyloo! - A Scottish warning yelled from a window before dumping
  3. a slop bucket on the street below.
  4. </div>

@model@inherits 可在同一视图中使用。@inherits 可位于视图导入的 _ViewImports.cshtml 文件中:

  1. @inherits CustomRazorPage<TModel>

下面的代码是一种强类型视图:

  1. @inherits CustomRazorPage<TModel>
  2. <div>The Login Email: @Model.Email</div>
  3. <div>Custom text: @CustomText</div>

如果在模型中传递“rick@contoso.com”,视图将生成以下 HTML 标记:

  1. <div>The Login Email: rick@contoso.com</div>
  2. <div>
  3. Custom text: Gardyloo! - A Scottish warning yelled from a window before dumping
  4. a slop bucket on the street below.
  5. </div>

@inject@inject

@inject 指令允许 Razor 页面将服务从服务容器注入到视图。有关详细信息,请参阅视图中的依赖关系注入

@layout@layout

此方案仅适用于 Razor 组件 (.razor)。

@layout 指令指定 Razor 组件的布局。布局组件用于避免代码重复和不一致。有关详细信息,请参阅 ASP.NET Core Blazor 布局

@model@model

此方案仅适用于 MVC 视图和 Razor Pages (.cshtml)。

@model 指令指定传递到视图或页面的模型类型:

  1. @model TypeNameOfModel

在使用个人用户帐户创建的 ASP.NET Core MVC 或 Razor Pages 应用中,Views/Account/Login.cshtml 包含以下模型声明:

  1. @model LoginViewModel

生成的类继承自 RazorPage<dynamic>

  1. public class _Views_Account_Login_cshtml : RazorPage<LoginViewModel>

Razor 公开了 Model 属性,用于访问传递到视图的模型:

  1. <div>The Login Email: @Model.Email</div>

@model 指令指定 Model 属性的类型。该指令将 T 中的 RazorPage<T> 指定为生成的类,视图便派生自该类。如果未指定 @model 指令,则 Model 属性的类型为 dynamic有关详细信息,请参阅强类型模型和 @model 关键字

@namespace@namespace

@namespace 指令:

  • 设置生成的 Razor 页面、MVC 视图或 Razor 组件的类的命名空间。
  • 从目录树中最近的导入文件、_ViewImports.cshtml(视图或页面)或 _Imports.razor (Razor) 中设置页面、视图或组件类的根派生命名空间。
  1. @namespace Your.Namespace.Here

对于下表中显示的 Razor Pages 示例:

  • 每个页面都导入 Pages/_ViewImports.cshtml。
  • Pages/_ViewImports.cshtml 包含@namespace Hello.World
  • 每个页面都有 Hello.World,作为其命名空间的根。
命名空间
Pages/Index.cshtmlHello.World
Pages/MorePages/Page.cshtmlHello.World.MorePages
Pages/MorePages/EvenMorePages/Page.cshtmlHello.World.MorePages.EvenMorePages

上述关系适用于与 MVC 视图和 Razor 组件一起使用的导入文件。

当多个导入文件具有 @namespace 指令时,最靠近目录树中的页面、视图或组件的文件将用于设置根命名空间。

如果前面示例中的 EvenMorePages 文件夹具有包含 的导入文件(或 Pages/MorePages/EvenMorePages/Page.cshtml 文件包含),则结果如下表所示@namespace Another.Planet``@namespace Another.Planet

命名空间
Pages/Index.cshtmlHello.World
Pages/MorePages/Page.cshtmlHello.World.MorePages
Pages/MorePages/EvenMorePages/Page.cshtmlAnother.Planet

@page@page

@page 指令具有不同的效果,具体取决于其所在文件的类型。指令:

.cshtml 文件第一行上的 @page 指令表示该文件是 Razor Page。有关详细信息,请参阅 ASP.NET Core 中的 Razor 页面介绍

@section@section

此方案仅适用于 MVC 视图和 Razor Pages (.cshtml)。

@section 指令与 MVC 和 Razor Pages 布局结合使用,允许视图或页面将内容呈现在 HTML 页面的不同部分。有关详细信息,请参阅 ASP.NET Core 中的布局

@using@using

@using 指令用于向生成的视图添加 C# using 指令:

  1. @using System.IO
  2. @{
  3. var dir = Directory.GetCurrentDirectory();
  4. }
  5. <p>@dir</p>

Razor 组件中,@using 还可控制哪些组件在范围内。

指令属性Directive attributes

@attributes@attributes

此方案仅适用于 Razor 组件 (.razor)。

@attributes 允许组件呈现未声明的属性。有关详细信息,请参阅 创建和使用 ASP.NET Core Razor 组件

@bind@bind

此方案仅适用于 Razor 组件 (.razor)。

组件中的数据绑定通过 @bind 属性实现。有关详细信息,请参阅 ASP.NET Core Blazor 数据绑定

@on{EVENT}@on{EVENT}

此方案仅适用于 Razor 组件 (.razor)。

Razor 为组件提供事件处理功能。有关详细信息,请参阅 ASP.NET Core Blazor 事件处理

@on{EVENT}:preventDefault@on{EVENT}:preventDefault

此方案仅适用于 Razor 组件 (.razor)。

禁止事件的默认操作。

@on{EVENT}:stopPropagation@on{EVENT}:stopPropagation

此方案仅适用于 Razor 组件 (.razor)。

停止事件的事件传播。

@key@key

此方案仅适用于 Razor 组件 (.razor)。

@key 指令属性使组件比较算法保证基于键的值保留元素或组件。有关详细信息,请参阅 创建和使用 ASP.NET Core Razor 组件

@ref@ref

此方案仅适用于 Razor 组件 (.razor)。

组件引用 (@ref) 提供了一种引用组件实例的方法,以便可以向该实例发出命令。有关详细信息,请参阅 创建和使用 ASP.NET Core Razor 组件

@typeparam@typeparam

此方案仅适用于 Razor 组件 (.razor)。

@typeparam 指令声明生成的组件类的泛型类型参数。有关详细信息,请参阅 ASP.NET Core Blazor 模板化组件

模板化 Razor 委托Templated Razor delegates

通过 Razor 模板,可使用以下格式定义 UI 代码片段:

  1. @<tag>...</tag>

下面的示例演示如何指定模板化 Razor 委托作为 Func<T,TResult>为委托封装的方法的参数指定动态类型对象类型指定为委托的返回值。该模板与 List<T>(具有 Pet 属性)的 Name 一起使用。

  1. public class Pet
  2. {
  3. public string Name { get; set; }
  4. }
  1. @{
  2. Func<dynamic, object> petTemplate = @<p>You have a pet named <strong>@item.Name</strong>.</p>;
  3. var pets = new List<Pet>
  4. {
  5. new Pet { Name = "Rin Tin Tin" },
  6. new Pet { Name = "Mr. Bigglesworth" },
  7. new Pet { Name = "K-9" }
  8. };
  9. }

使用 pets 语句提供的 foreach 呈现该模板:

  1. @foreach (var pet in pets)
  2. {
  3. @petTemplate(pet)
  4. }

呈现的输出:

  1. <p>You have a pet named <strong>Rin Tin Tin</strong>.</p>
  2. <p>You have a pet named <strong>Mr. Bigglesworth</strong>.</p>
  3. <p>You have a pet named <strong>K-9</strong>.</p>

还可以提供内联 Razor 模板作为方法的参数。如下示例中,Repeat 方法收到一个 Razor 模板。该方法使用模板生成 HTML 内容,其中包含列表中提供的重复项:

  1. @using Microsoft.AspNetCore.Html
  2. @functions {
  3. public static IHtmlContent Repeat(IEnumerable<dynamic> items, int times,
  4. Func<dynamic, IHtmlContent> template)
  5. {
  6. var html = new HtmlContentBuilder();
  7. foreach (var item in items)
  8. {
  9. for (var i = 0; i < times; i++)
  10. {
  11. html.AppendHtml(template(item));
  12. }
  13. }
  14. return html;
  15. }
  16. }

使用前面示例中的 pets 列表,调用 Repeat 方法以及:

  • ListPet
  • 每只宠物的重复次数。
  • 用于无序列表的列表项的内联模板。
  1. <ul>
  2. @Repeat(pets, 3, @<li>@item.Name</li>)
  3. </ul>

呈现的输出:

  1. <ul>
  2. <li>Rin Tin Tin</li>
  3. <li>Rin Tin Tin</li>
  4. <li>Rin Tin Tin</li>
  5. <li>Mr. Bigglesworth</li>
  6. <li>Mr. Bigglesworth</li>
  7. <li>Mr. Bigglesworth</li>
  8. <li>K-9</li>
  9. <li>K-9</li>
  10. <li>K-9</li>
  11. </ul>

标记帮助程序Tag Helpers

此方案仅适用于 MVC 视图和 Razor Pages (.cshtml)。

标记帮助程序有三个相关指令。

指令函数
@addTagHelper向视图提供标记帮助程序。
@removeTagHelper从视图中删除以前添加的标记帮助程序。
@tagHelperPrefix指定标记前缀,以启用标记帮助程序支持并阐明标记帮助程序的用法。

Razor 保留关键字Razor reserved keywords

Razor 关键字Razor keywords

  • page(需要 ASP.NET Core 2.1 或更高版本)
  • 命名空间
  • functions
  • 继承
  • model
  • section
  • helper(ASP.NET Core 当前不支持)

Razor 关键字使用 @(Razor Keyword) 进行转义(例如,@(functions))。

C# Razor 关键字C# Razor keywords

  • case
  • do
  • default
  • for
  • foreach
  • if
  • else
  • lock
  • 开关
  • 尝试
  • catch
  • finally
  • 借助
  • while

C# Razor 关键字必须使用 @(@C# Razor Keyword) 进行双转义(例如,@(@case))。第一个 @ 对 Razor 分析器转义。第二个 @ 对 C# 分析器转义。

Razor 不使用的保留关键字Reserved keywords not used by Razor

  • class

检查为视图生成的 Razor C# 类Inspect the Razor C# class generated for a view

在 .NET Core SDK 2.1 或更高版本中,Razor SDK 负责编译 Razor 文件。生成项目时,Razor SDK 在项目根目录中生成 obj/<build_configuration>/<target_framework_moniker>/Razor 目录。Razor 目录中的目录结构反映项目的目录结构。

在面向 .NET Core 2.1 的 ASP.NET Core 2.1 Razor Pages 项目中,请考虑以下目录结构:

  • Areas/
    • Admin/
      • Pages/
        • Index.cshtml
        • Index.cshtml.cs
  • Pages/
    • Shared/
      • _Layout.cshtml
    • _ViewImports.cshtml
    • _ViewStart.cshtml
    • Index.cshtml
    • Index.cshtml.cs

在 Debug 配置下生成项目将生成以下 obj 目录:

  • obj/
    • Debug/
      • netcoreapp2.1/
        • Razor/
          • Areas/
            • Admin/
              • Pages/
                • Index.g.cshtml.cs
          • Pages/
            • Shared/
              • _Layout.g.cshtml.cs
            • _ViewImports.g.cshtml.cs
            • _ViewStart.g.cshtml.cs
            • Index.g.cshtml.cs

若要查看 Pages/Index.cshtml 的生成类,请打开 obj/Debug/netcoreapp2.1/Razor/Pages/Index.g.cshtml.cs。

将下面的类添加到 ASP.NET Core MVC 项目:

  1. using Microsoft.AspNetCore.Mvc.Razor.Extensions;
  2. using Microsoft.AspNetCore.Razor.Language;
  3. public class CustomTemplateEngine : MvcRazorTemplateEngine
  4. {
  5. public CustomTemplateEngine(RazorEngine engine, RazorProject project)
  6. : base(engine, project)
  7. {
  8. }
  9. public override RazorCSharpDocument GenerateCode(RazorCodeDocument codeDocument)
  10. {
  11. var csharpDocument = base.GenerateCode(codeDocument);
  12. var generatedCode = csharpDocument.GeneratedCode;
  13. // Look at generatedCode
  14. return csharpDocument;
  15. }
  16. }

Startup.ConfigureServices 中,使用 RazorTemplateEngine 类替代 MVC 添加的 CustomTemplateEngine

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddMvc();
  4. services.AddSingleton<RazorTemplateEngine, CustomTemplateEngine>();
  5. }

return csharpDocument;CustomTemplateEngine 语句上设置断点。当程序执行在断点处停止时,查看 generatedCode 的值。

generatedCode 的文本可视化工具视图

视图查找和区分大小写View lookups and case sensitivity

Razor 视图引擎为视图执行区分大小写的查找。但是,实际查找取决于基础文件系统:

  • 基于文件的源:
    • 在使用不区分大小写的文件系统的操作系统(例如,Windows)上,物理文件提供程序查找不区分大小写。例如,return View("Test") 可匹配 /Views/Home/Test.cshtml/Views/home/test.cshtml 以及任何其他大小写变体。
    • 在区分大小写的文件系统(例如,Linux、OSX 以及使用 EmbeddedFileProvider 构建的文件系统)上,查找区分大小写。例如,return View("Test") 专门匹配 /Views/Home/Test.cshtml
  • 预编译视图:在 ASP.NET Core 2.0 及更高版本中,预编译视图查找在所有操作系统上均不区分大小写。该行为与 Windows 上物理文件提供程序的行为相同。如果两个预编译视图仅大小写不同,则查找的结果具有不确定性。

建议开发人员将文件和目录名称的大小写与以下项的大小写匹配:

  • 区域、控制器和操作名称。
  • Razor 页面。

匹配大小写可确保无论使用哪种基础文件系统,部署都能找到其视图。