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 Razor 组件

标记帮助程序的功能

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> 用于包含 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.cshtmlPages文件夹及其子目录中的所有视图文件都会默认继承它,使得标记帮助程序可用。 上面的代码使用通配符语法(“*”)指定:指定程序集 (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 会删除该视图中的指定标记帮助程序。 在Views/Folder/_ViewImports.cshtml文件中使用@removeTagHelper,将从Folder中的所有视图删除指定的标记帮助程序。

使用_ViewImports.cshtml文件控制标记帮助程序作用域

可将_ViewImports.cshtml添加到任何视图文件夹,视图引擎将同时应用该文件和Views/_ViewImports.cshtml文件中的指令。 如果为Home视图添加空的Views/Home/_ViewImports.cshtml文件,不会发生任何更改,因为_ViewImports.cshtml文件是附加的。 添加到Views/Home/_ViewImports.cshtml文件(不在默认Views/_ViewImports.cshtml文件中)的任何@addTagHelper指令,都只会将这些标记帮助程序公开给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 markup with Tag Helper prefix set to

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

自结束标记帮助程序

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

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

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

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

前面的代码可以编写为:

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

通常,@运算符会将表达式的文本表示形式插入到呈现的 HTML 标记中。 但是,当表达式的计算结果为逻辑false时,框架会删除该属性。 在前面的示例中,如果ModelLicenseIdnull,则disabled属性设置为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 就会显示匹配的元素:

After typing

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

The

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

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

Example

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

The user has typed an opening bracket and the HTML element name

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

The user has typed an opening bracket, the HTML element name

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

The user selected

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

The user types

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

The user types

The user types

标记帮助程序与 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 就会显示匹配的元素:

The user types

IntelliSense 可帮助编写整行。

以下代码图像显示了由 Visual Studio 包含的 ASP.NET 4.5.x MVC 模板生成的Views/Account/Register.cshtmlRazor视图的 Form 部分。

Razor markup for the form portion of the Register Razor view for ASP.NET 4.5 MVC project template

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

@Html.AntiForgeryToken()

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

Razor markup with Tag Helpers for the form portion of the Register Razor view for an ASP.NET Core project template

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

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

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

Options dialog in Visual Studio

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

定位点

缓存

组件

分布式缓存

环境

表单

表单操作

Image

输入

标签

链接

Partial

保留组件状态

脚本

选择

Textarea

验证消息

验证摘要

其他资源