ASP.NET Core 中的标记帮助程序

作者:Rick Anderson

什么是标记帮助程序

标记帮助程序使服务器端代码可以在 Razor 文件中参与创建和呈现 HTML 元素。 例如,内置 ImageTagHelper 可以将版本号追加到图像名称。 每当图像发生变化时,服务器都会为图像生成一个新的唯一版本,因此客户端总能获得当前图像(而不是过时的缓存图像)。 有多种常见任务(例如创建表单、链接,加载资产等)的内置标记帮助程序,公共 GitHub 存储库和 NuGet 包中甚至还有更多可用标记帮助程序。 标记帮助程序使用 C# 创建,基于元素名称、属性名称或父标记以 HTML 元素为目标。 例如,应用 LabelTagHelper 属性时,内置 LabelTagHelper 可以 HTML <label> 元素为目标。 如果熟悉 HTML 帮助程序,标记帮助程序可以减少 Razor 视图中 HTML 和 C# 之间的显式转换。 在很多情况下,HTML 帮助程序为特定标记帮助程序提供了一种替代方法,但标记帮助程序不会替代 HTML 帮助程序,且并非每个 HTML 帮助程序都有对应的标记帮助程序,认识到这点也很重要。 标记帮助程序与 HTML 帮助程序的比较更详细地介绍了两者之间的差异。

组件不支持 Razor 标记帮助程序。 有关详细信息,请参阅 ASP.NET Core 组件。

标记帮助程序的功能

HTML 易用开发体验

使用标记帮助程序的 Razor 标记在很大程度上看起来像是标准 HTML。 熟悉 HTML/CSS/JavaScript 的前端设计师无需学习 C# Razor 语法即可编辑 Razor。

用于创建 HTML 和 Razor 标记的丰富 IntelliSense 环境

这与 HTML 帮助程序形成鲜明对比,HTML 帮助程序是 Razor 视图中标记的曾用服务器端创建方法。 标记帮助程序与 HTML 帮助程序的比较更详细地介绍了两者之间的差异。 标记帮助程序的 IntelliSense 支持解释了 IntelliSense 环境。 即使是熟悉 Razor C# 语法的开发人员,使用标记帮助程序也比编写 C# Razor 标记更高效。

使用仅在服务器上可用的信息,可提高生产力,并能生成更稳定、可靠和可维护的代码

例如,过去更新图像时,必须在更改图像时更改图像名称。 出于性能原因,要主动缓存图像,而若不更改图像的名称,客户端就可能获得过时的副本。 以前,编辑完图像后,必须更改名称,而且需要更新 Web 应用中对该图像的每个引用。 这不仅是这个非常费力的,它也容易出错, (你可以错过引用,意外输入错误的字符串,等等,) 内置 ImageTagHelper 可以自动执行此操作。 ImageTagHelper 可将版本号追加到图像名称,这样每当图像出现更改时,服务器都会自动为该图像生成新的唯一版本。 客户端总是能获得最新图像。 使用 ImageTagHelper 实质上是免费获得稳健性而节省劳动力。

大多数内置标记帮助程序以标准 HTML 元素为目标,为该元素提供服务器端属性。 例如,<input>Views/Account 文件夹中许多视图中使用的元素包含该asp-for属性。 此特性将指定模型属性的名称提取至所呈现的 HTML。 以一个具备以下模型的 Razor 视图为例:

public class Movie
{
    public int ID { get; set; }
    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }
    public decimal Price { get; set; }
}

以下 Razor 标记:

<label asp-for="Movie.Title"></label>

则会生成以下 HTML:

<label for="Movie_Title">Title</label>

通过 LabelTagHelper 中的 For 属性,可使用 asp-for 特性。 请参阅创作标记帮助程序,获取详细信息。

管理标记帮助程序作用域

标记帮助程序作用域由 @addTagHelper@removeTagHelper 和“!”选择退出字符联合控制。

使用 @addTagHelper 添加标记帮助程序

如果创建了名为 AuthoringTagHelpers 的新 ASP.NET Core Web 应用,则会将以下Views/_ViewImports.cshtml文件添加到项目中:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, AuthoringTagHelpers

@addTagHelper 指令让视图可以使用标记帮助程序。 在这种情况下,视图文件 Pages/_ViewImports.cshtml是默认情况下由 Pages 文件夹和子文件夹中的所有文件继承的;使标记帮助程序可用。 上面的代码使用通配符语法(“*”)指定:指定程序集 (Microsoft.AspNetCore.Mvc.TagHelpers) 中的所有标记帮助程序对于 Views 目录或子目录中的所有视图文件均可用。 @addTagHelper 后第一个参数指定要加载的标记帮助程序(我们使用“*”指定加载所有标记帮助程序),第二个参数“Microsoft.AspNetCore.Mvc.TagHelpers”指定包含标记帮助程序的程序集。 Microsoft.AspNetCore.Mvc.TagHelpers 是内置 ASP.NET Core 标记帮助程序的程序集。

要公开此项目中的所有标记帮助程序(将创建名为 AuthoringTagHelpers 的程序集),可使用以下内容:

@using AuthoringTagHelpers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, AuthoringTagHelpers

如果项目包含具有默认命名空间 (AuthoringTagHelpers.TagHelpers.EmailTagHelper) 的 EmailTagHelper,则可提供标记帮助程序的完全限定名称 (FQN):

@using AuthoringTagHelpers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper AuthoringTagHelpers.TagHelpers.EmailTagHelper, AuthoringTagHelpers

若要使用 FQN 将标记帮助程序添加到视图中,请先添加 FQN () AuthoringTagHelpers.TagHelpers.EmailTagHelper ,然后将程序集名称 (AuthoringTagHelpers) 。 大多数开发人员更喜欢使用“*”通配符语法。 使用通配符语法,可在 FQN 中插入通配符“*”作为后缀。 例如,以下任何指令都将引入 EmailTagHelper

@addTagHelper AuthoringTagHelpers.TagHelpers.E*, AuthoringTagHelpers
@addTagHelper AuthoringTagHelpers.TagHelpers.Email*, AuthoringTagHelpers

如前所述,将 @addTagHelper 指令添加到 Views/_ViewImports.cshtml 文件会使标记帮助程序可用于 Views 目录和子目录中的所有视图文件。 如果想选择仅对特定视图公开标记帮助程序,可在这些视图文件中使用 @addTagHelper 指令。

@removeTagHelper 删除标记帮助程序

@removeTagHelper@addTagHelper 具有相同的两个参数,它会删除之前添加的标记帮助程序。 例如,应用于特定视图的 @removeTagHelper 会删除该视图中的指定标记帮助程序。 在文件中使用@removeTagHelper将从文件夹中的所有视图中删除指定的标记帮助程序。Views/Folder/_ViewImports.cshtml

使用 _ViewImports.cshtml 文件控制标记帮助程序范围

你可以向任何视图文件夹添加 a, _ViewImports.cshtml 并且视图引擎会从该文件和 Views/_ViewImports.cshtml 文件应用指令。 如果为Home视图添加了空Views/Home/_ViewImports.cshtml文件,则不会发生任何更改,因为_ViewImports.cshtml该文件是累加的。 @addTagHelper添加到Views/Home/_ViewImports.cshtml文件的任何指令 (不在默认Views/_ViewImports.cshtml文件中) 只会将这些标记帮助程序公开到文件夹中的Home视图。

选择退出各个元素

使用标记帮助程序选择退出字符(“!”),可在元素级别禁用标记帮助程序。 例如,使用标记帮助程序选择退出字符在 <span> 中禁用 Email 验证:

<!span asp-validation-for="Email" class="text-danger"></!span>

须将标记帮助程序选择退出字符应用于开始和结束标记。 (将选择退出字符添加到开始标记时,Visual Studio 编辑器会自动为结束标记添加相应字符)。 添加选择退出字符后,元素和标记帮助程序属性不再以独特字体显示。

使用 @tagHelperPrefix 阐明标记帮助程序用途

@tagHelperPrefix 指令可指定一个标记前缀字符串,以启用标记帮助程序支持并阐明标记帮助程序用途。 例如,可以将以下标记添加到 Views/_ViewImports.cshtml 文件中:

@tagHelperPrefix th:

在以下代码图像中,标记帮助程序前缀设置为 th:,所以只有使用前缀 th: 的元素才支持标记帮助程序(可使用标记帮助程序的元素以独特字体显示)。 <label><input> 元素具有标记帮助程序前缀,可使用标记帮助程序,而 <span> 元素则相反。

Razor 标记帮助程序前缀设置为标签和输入元素名称的“th:” 标记

适用于 @addTagHelper 的层次结构规则也适用于 @tagHelperPrefix

自结束标记帮助程序

许多标记帮助程序都不能用作自结束标记。 某些标记帮助程序被设计为自结束标记。 使用未被设计为自结束的标记帮助程序会抑制呈现的输出。 自结束标记帮助程序会在呈现的输出中生成自结束标记。 有关详细信息,请在创作标记帮助程序中查看此问题

标记帮助程序属性/声明中的 C#

标记帮助程序不允许在元素的属性或标记声明区域中出现 C#。 例如,以下代码是无效的:

<input asp-for="LastName"  
       @(Model?.LicenseId == null ? "disabled" : string.Empty) />

前面的代码可以编写为:

<input asp-for="LastName" 
       disabled="@(Model?.LicenseId == null)" />

通常, @ 运算符将表达式的文本表示形式插入到呈现的 HTML 标记中。 但是,当表达式的计算结果为逻辑 false时,框架会删除该属性。 在前面的示例中,如果disabled任一ModelLicenseIdnull者都设置为true该属性。

标记帮助程序初始值设定项

虽然属性可用于配置标记帮助程序的各个实例, ITagHelperInitializer<TTagHelper> 但可用于配置特定类型的所有标记帮助程序实例。 请考虑以下标记帮助程序初始值设定项的示例,该初始值设定项为应用中的所有实例ScriptTagHelper配置asp-append-version属性或AppendVersion属性:

public class AppendVersionTagHelperInitializer : ITagHelperInitializer<ScriptTagHelper>
{
    public void Initialize(ScriptTagHelper helper, ViewContext context)
    {
        helper.AppendVersion = true;
    }
}

若要使用初始值设定项,请将其注册为应用程序的启动的一部分对其进行配置:

builder.Services.AddSingleton
    <ITagHelperInitializer<ScriptTagHelper>, AppendVersionTagHelperInitializer>();

在 wwwroot 外部标记帮助程序自动生成版本

有关标记帮助程序为外部 wwwroot静态文件生成版本,请参阅 来自多个位置的文件

标记帮助程序的 Intellisense 支持

请考虑编写 HTML <label> 元素。 只要在 Visual Studio 编辑器中输入 <l,IntelliSense 就会显示匹配的元素:

在键盘上键入“l”后,IntelliSense 会建议选择“label”的可能标记名称列表。

不仅会获得 HTML 帮助,还会有图标(下方带有“<>”的“@”符号)。

其下带有“@”的“@”<>符号。

该图标将元素标识为标记帮助程序的目标。 纯 HTML 元素(如 fieldset)显示“<>”图标。

纯 HTML <label> 标记以棕色字体显示 HTML 标记(使用默认 Visual Studio 颜色主题时),以红色字体显示属性,并以蓝色字体显示属性值。

示例“label”HTMl 标记

输入 <label 后,IntelliSense 会列出可用的 HTML/CSS 属性和以标记帮助程序为目标的属性:

用户已键入左括号和 HTML 元素名称“label”。IntelliSense 提供了可能的属性列表, (未预选) 。

通过 IntelliSense 语句完成功能,按 Tab 键即可用选择的值完成语句:

用户已键入左括号、HTML 元素名称“label”,并开始键入属性名称 (“as”) 。IntelliSense 提供了一个已选中“asp-for”的建议对话框。

只要输入标记帮助程序属性,标记和属性字体就会更改。 如果使用默认的 Visual Studio“蓝色”或“浅色”颜色主题,则字体是粗体紫色。 如果使用“深色”主题,则字体为粗体青色。 本文档中的图像在使用默认主题时截取的。

用户选择了“asp-for”,因为用户未使用深色主题,因此现在以粗体紫色显示。

在双引号 ("") 内输入 Visual Studio CompleteWord 快捷方式(默认值为 Ctrl+空格键),即可使用 C#,就像在 C# 类中一样。 IntelliSense 会显示页面模型上的所有方法和属性。 由于属性类型是 ModelExpression,所以这些方法和属性可用。 在下图中,我正在编辑 Register 视图,所以 RegisterViewModel 是可用的。

用户在“asp-for”属性的值中键入“e”。IntelliSense 建议在选中“Email”的情况下完成。

IntelliSense 会列出页面上模型可用的属性和方法。 丰富 IntelliSense 环境可帮助选择 CSS 类:

用户键入“cl”,将属性添加到“input”元素。IntelliSense 提供了一个完成建议列表,其中选择了“class”。

用户键入“co”作为“input”元素的“class”属性的值。IntelliSense 提供了一系列完成建议,其中选择了“col”。

标记帮助程序与 HTML 帮助程序的比较

标记帮助程序附加到 Razor 视图中的 HTML 元素,HTML 帮助程序是作为与 Razor 视图中 HTML 交织的方法被调用的。 以下列 Razor 标记为例,它创建具有 CSS 类“caption”的 HTML 标签:

@Html.Label("FirstName", "First Name:", new {@class="caption"})

艾特 (@) 符号告诉 Razor 这是代码的开头。 接下来的两个参数(“FirstName”和“First Name:”)是字符串,所以 IntelliSense 无法提供帮助。 最后一个参数:

new {@class="caption"}

是用于表示属性的匿名对象。 由于 class 是 C# 中的保留关键字,因此要使用 @ 符号强制 C# 将 @class= 解释为符号(属性名称)。 对于前端设计师(熟悉 HTML/CSS/JavaScript 及其他客户端技术,但不熟悉 C# 和 Razor 的人),这行代码中大部分内容都很陌生。 必须在没有 IntelliSense 帮助的情况下编写整行代码。

使用 LabelTagHelper,相同标记可以编写为:

<label class="caption" asp-for="FirstName"></label>

使用标记帮助程序版本,只要在 Visual Studio 编辑器中输入 <l,IntelliSense 就会显示匹配的元素:

用户在键盘上键入“l”。IntelliSense 建议选择“label”的 HTML 元素完成。

IntelliSense 可帮助编写整行。

以下代码图像显示了从 Visual Studio 随附的 ASP.NET 4.5.x MVC 模板生成的视图的 Views/Account/Register.cshtmlRazor 窗体部分。

Razor ASP.NET 4.5 MVC 项目模板的“注册 Razor ”视图的表单部分的标记

Visual Studio 编辑器以灰色背景显示 C# 代码。 例如,AntiForgeryToken HTML 帮助程序:

@Html.AntiForgeryToken()

以灰色背景显示。 Register 视图中的标记大部分是 C#。 将其与使用标记帮助程序的等效方法进行比较:

Razor标记帮助程序用于 ASP.NET Core项目模板的“注册Razor”视图的表单部分的标记

与 HTML 帮助程序方法相比,此标记更清晰,更容易阅读、编辑和维护。 C# 代码会被减少至服务器需要知道的最小值。 Visual Studio 编辑器以独特的字体显示标记帮助程序的目标标记。

请考虑 Email 组:

<div class="form-group">
    <label asp-for="Email" class="col-md-2 control-label"></label>
    <div class="col-md-10">
        <input asp-for="Email" class="form-control" />
        <span asp-validation-for="Email" class="text-danger"></span>
    </div>
</div>

每个“asp-”属性都有一个“Email”值,但是“Email”不是字符串。 在此上下文中,“Email”是 RegisterViewModel 的 C# 模型表达式属性。

Visual Studio 编辑器可帮助编写注册窗体的标记帮助程序方法中的所有标记,而 Visual Studio 不会为 HTML 帮助程序方法中的大多数代码提供帮助。 标记帮助程序的 IntelliSense 支持详细介绍了如何在 Visual Studio 编辑器中使用标记帮助程序。

标记帮助程序与 Web 服务器控件的比较

  • 标记帮助程序不拥有与其相关的元素:它们只是参与元素和内容的呈现。 ASP.NET Web 服务器控件在页面上进行声明和调用。

  • ASP.NET Web 服务器控件具有可观的生命周期,因而难以进行开发和调试。

  • 通过 Web 服务器控件,可使用客户端控件向客户端文档对象模型 (DOM) 元素添加功能。 标记帮助程序没有 DOM。

  • Web 服务器控件包括自动浏览器检测。 标记帮助程序不了解浏览器。

  • 通常不能撰写 Web 服务器控件时,多个标记帮助程序可作用于同一元素(请参阅避免标记帮助程序冲突)。

  • 标记帮助程序可以修改其作用域内 HTML 元素的标记和内容,但不会直接修改页面上的其他内容。 Web 服务器控件的作用域较广,并且可以执行影响页面其他部分的操作,从而可能造成意想不到的副作用。

  • Web 服务器控件使用类型转换器将字符串转换为对象。 使用标记帮助程序时,本身就用 C# 语言工作,因此无需进行类型转换。

  • Web Server 控件用于 System.ComponentModel 实现组件和控件的运行时和设计时行为。 System.ComponentModel 包括用于属性和类型转换器的实现、数据源绑定和组件授权的基类和接口。 与通常派生自 TagHelper 的标记帮助程序相比,TagHelper 基类仅公开两个方法,即 ProcessProcessAsync

自定义标记帮助程序元素字体

可以在“工具”>“选项”>“环境”>“字体和颜色”中自定义字体和着色:

Visual Studio 中的“选项”对话框

内置 ASP.NET Core 标记帮助程序

定位点标记帮助程序

缓存标记帮助程序

组件标记帮助程序

分布式缓存帮助程序

环境标记帮助程序

表单标记帮助程序

窗体操作标记帮助程序

图像标记帮助程序

输入标记帮助程序

标签标记帮助程序

链接标记帮助程序

分部标记帮助程序

脚本标记帮助程序

选择标记帮助程序

文本区标记帮助程序

验证消息标记帮助程序

验证摘要标记帮助程序

其他资源