在 ASP.NET Core 中创作标记帮助程序Author Tag Helpers in ASP.NET Core

本文内容

作者:Rick Anderson

查看或下载示例代码如何下载

标记帮助程序入门Get started with Tag Helpers

本教程介绍标记帮助程序编程。标记帮助程序简介描述了标记帮助程序提供的优势。

标记帮助程序是实现 ITagHelper 接口的任何类。但是,在创作标记帮助程序时,通常从 TagHelper 派生,这样可以访问 Process 方法。

  • 创建一个名为 AuthoringTagHelpers 的新 ASP.NET Core 项目。此项目不需要身份验证。

  • 创建一个名为“TagHelpers”的文件夹来保存标记帮助程序。“TagHelpers”文件夹不是必需的,但它是合理的约定。现在让我们开始编写一些简单的标记帮助程序。

最小的标记帮助程序A minimal Tag Helper

在本部分中,你将编写一个更新电子邮件标记的标记帮助程序。例如:

  1. <email>Support</email>

服务器将使用电子邮件标记帮助程序将该标记转换为以下内容:

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

即,使其成为电子邮件链接的定位标记。如果你正在编写博客引擎,并且需要它将营销、支持和其他联系人的电子邮件全部发送到同一个域,则可能需要执行此操作。

  • 将以下 EmailTagHelper 类添加到“TagHelpers”文件夹。
  1. using Microsoft.AspNetCore.Razor.TagHelpers;
  2. using System.Threading.Tasks;
  3. namespace AuthoringTagHelpers.TagHelpers
  4. {
  5. public class EmailTagHelper : TagHelper
  6. {
  7. public override void Process(TagHelperContext context, TagHelperOutput output)
  8. {
  9. output.TagName = "a"; // Replaces <email> with <a> tag
  10. }
  11. }
  12. }
  • 标记帮助程序使用面向根类名称的元素的命名约定(减去类名称的 TagHelper 部分)。在此示例中,EmailTagHelper 的根名称是 email,因此 标记将作为目标名称<email>。此命名约定应适用于大多数标记帮助程序,稍后将介绍如何重写它。

  • EmailTagHelper 类派生自 TagHelperTagHelper 类提供编写标记帮助程序的方法和属性。

  • 重写的 Process 方法控制标记帮助程序在执行时的操作。TagHelper 类还提供具有相同参数的异步版本 (ProcessAsync)。

  • Process(和 ProcessAsync)的上下文参数包含与执行当前 HTML 标记相关的信息。

  • Process(和 ProcessAsync)的输出参数包含监控状态的 HTML 元素,它代表用于生成 HTML 标记和内容的原始源。

  • 类名称的后缀是 TagHelper,这不是必需的,但被认为是最佳做法约定。可将类声明为:

  1. public class Email : TagHelper
  • 要使 EmailTagHelper 类可用于所有 Razor 视图,请将 addTagHelper 指令添加到 Views/_ViewImports.cshtml 文件:
  1. @using AuthoringTagHelpers
  2. @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
  3. @addTagHelper *, AuthoringTagHelpers

上面的代码使用通配符语法来指定程序集中的所有标记帮助程序都将可用。@addTagHelper 之后的第一个字符串指定要加载的标记帮助程序(对所有标记帮助程序使用“*”),第二个字符串“AuthoringTagHelpers”指定标记帮助程序所在的程序集。另请注意,第二行将使用通配符语法 ASP.NET Core MVC 标记帮助程序(标记帮助程序简介中讨论了这些帮助程序。)这是使标记帮助程序可用于 Razor 视图的 @addTagHelper 指令。或者,也可以提供标记帮助程序的完全限定的名称 (FQN),如下所示:

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

若要使用 FQN 将标记帮助程序添加到视图中,请依次添加 FQN (AuthoringTagHelpers.TagHelpers.EmailTagHelper) 和程序集名称(AuthoringTagHelpers,不一定是 namespace)。大多数开发者更喜欢使用通配符语法。标记帮助程序简介详细介绍了标记帮助程序的添加和删除方法,以及层次结构和通配符语法。

  • 使用以下更改更新 Views/Home/Contact.cshtml 文件中的标记:
  1. @{
  2. ViewData["Title"] = "Contact";
  3. }
  4. <h2>@ViewData["Title"].</h2>
  5. <h3>@ViewData["Message"]</h3>
  6. <address>
  7. One Microsoft Way<br />
  8. Redmond, WA 98052<br />
  9. <abbr title="Phone">P:</abbr>
  10. 425.555.0100
  11. </address>
  12. <address>
  13. <strong>Support:</strong><email>Support</email><br />
  14. <strong>Marketing:</strong><email>Marketing</email>
  15. </address>
  • 运行应用并使用你喜爱的浏览器来查看 HTML 源,以便验证电子邮件标记是否替换为定位标记(例如,<a>Support</a>)。Support 和 Marketing 呈现为链接,但它们不具备使其正常工作的 属性href。此问题将在下一部分得以解决。

SetAttribute 和 SetContentSetAttribute and SetContent

在本部分中,我们将更新 EmailTagHelper,使其能够为电子邮件创建有效的定位标记。我们将对其进行更新以获取 Razor 视图中的信息(采用 mail-to 属性的形式)并使用该信息来生成定位点。

使用以下内容更新 EmailTagHelper 类:

  1. public class EmailTagHelper : TagHelper
  2. {
  3. private const string EmailDomain = "contoso.com";
  4. // Can be passed via <email mail-to="..." />.
  5. // PascalCase gets translated into kebab-case.
  6. public string MailTo { get; set; }
  7. public override void Process(TagHelperContext context, TagHelperOutput output)
  8. {
  9. output.TagName = "a"; // Replaces <email> with <a> tag
  10. var address = MailTo + "@" + EmailDomain;
  11. output.Attributes.SetAttribute("href", "mailto:" + address);
  12. output.Content.SetContent(address);
  13. }
  14. }
  • 标记帮助程序采用 Pascal 大小写格式的类和属性名将转换为各自相应的短横线格式。因此,要使用 MailTo 属性,请使用 <email mail-to="value"/> 等效项。

  • 最后一行为最小功能标记帮助程序设置已完成的内容。

  • 突出显示的行显示了添加属性的语法:

  1. public override void Process(TagHelperContext context, TagHelperOutput output)
  2. {
  3. output.TagName = "a"; // Replaces <email> with <a> tag
  4. var address = MailTo + "@" + EmailDomain;
  5. output.Attributes.SetAttribute("href", "mailto:" + address);
  6. output.Content.SetContent(address);
  7. }

只要属性集合中当前不存在“href”属性,该方法就适用于此属性。也可使用 output.Attributes.Add 方法将标记帮助程序属性添加到标记属性集合的末尾。

  • 使用以下更改更新 Views/Home/Contact.cshtml 文件中的标记:
  1. @{
  2. ViewData["Title"] = "Contact Copy";
  3. }
  4. <h2>@ViewData["Title"].</h2>
  5. <h3>@ViewData["Message"]</h3>
  6. <address>
  7. One Microsoft Way Copy Version <br />
  8. Redmond, WA 98052-6399<br />
  9. <abbr title="Phone">P:</abbr>
  10. 425.555.0100
  11. </address>
  12. <address>
  13. <strong>Support:</strong><email mail-to="Support"></email><br />
  14. <strong>Marketing:</strong><email mail-to="Marketing"></email>
  15. </address>
  • 运行应用并验证它是否生成正确的链接。

备注

如果打算编写电子邮件标记自结束 (<email mail-to="Rick" />),最终输出也将为自结束。要启用只使用开始标记 (<email mail-to="Rick">) 来编写标记的功能,必须用以下内容来标记类:

  1. [HtmlTargetElement("email", TagStructure = TagStructure.WithoutEndTag)]
  2. public class EmailVoidTagHelper : TagHelper
  3. {
  4. private const string EmailDomain = "contoso.com";
  5. // Code removed for brevity

鉴于自结束电子邮件标记帮助程序,输出将为 <a href="mailto:Rick@contoso.com" />自结束定位标记不是有效的 HTML,因此你不想创建这样的标记,但你可能想要创建一个自结束的标记帮助程序。标记帮助程序在读取标记后设置 TagMode 属性的类型。

ProcessAsyncProcessAsync

在本部分中,我们将编写异步电子邮件帮助程序。

  • EmailTagHelper 类替换为以下代码:
  1. public class EmailTagHelper : TagHelper
  2. {
  3. private const string EmailDomain = "contoso.com";
  4. public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
  5. {
  6. output.TagName = "a"; // Replaces <email> with <a> tag
  7. var content = await output.GetChildContentAsync();
  8. var target = content.GetContent() + "@" + EmailDomain;
  9. output.Attributes.SetAttribute("href", "mailto:" + target);
  10. output.Content.SetContent(target);
  11. }
  12. }

注意:

  • 此版本使用异步 ProcessAsync 方法。异步 GetChildContentAsync 返回包含 TaskTagHelperContent

  • 使用 output 参数获取 HTML 元素的内容。

  • 对 Views/Home/Contact.cshtml 文件进行以下更改,以便标记帮助程序能够获取目标电子邮件。
  1. @{
  2. ViewData["Title"] = "Contact";
  3. }
  4. <h2>@ViewData["Title"].</h2>
  5. <h3>@ViewData["Message"]</h3>
  6. <address>
  7. One Microsoft Way<br />
  8. Redmond, WA 98052<br />
  9. <abbr title="Phone">P:</abbr>
  10. 425.555.0100
  11. </address>
  12. <address>
  13. <strong>Support:</strong><email>Support</email><br />
  14. <strong>Marketing:</strong><email>Marketing</email>
  15. </address>
  • 运行应用并验证它是否生成有效的电子邮件链接。

RemoveAll、PreContent.SetHtmlContent 和 PostContent.SetHtmlContentRemoveAll, PreContent.SetHtmlContent and PostContent.SetHtmlContent

  • 将以下 BoldTagHelper 类添加到“TagHelpers”文件夹。
  1. using Microsoft.AspNetCore.Razor.TagHelpers;
  2. namespace AuthoringTagHelpers.TagHelpers
  3. {
  4. [HtmlTargetElement(Attributes = "bold")]
  5. public class BoldTagHelper : TagHelper
  6. {
  7. public override void Process(TagHelperContext context, TagHelperOutput output)
  8. {
  9. output.Attributes.RemoveAll("bold");
  10. output.PreContent.SetHtmlContent("<strong>");
  11. output.PostContent.SetHtmlContent("</strong>");
  12. }
  13. }
  14. }
  • [HtmlTargetElement] 属性传递一个属性参数,该参数指定包含名为“bold”的 HTML 属性的任何 HTML 元素都将匹配,并且该类中的 Process 重写方法将会运行。在此示例中,Process 方法删除了“bold”属性,并用 <strong></strong> 围住了包含的标记。

  • 因为你不想替换现有的标记内容,所以必须用 <strong> 方法编写开头的 PreContent.SetHtmlContent 标记,并用 </strong> 方法编写结尾的 PostContent.SetHtmlContent 标记。

  • 修改 About.cshtml 视图,以包含 属性值bold。完成的代码如下所示。
  1. @{
  2. ViewData["Title"] = "About";
  3. }
  4. <h2>@ViewData["Title"].</h2>
  5. <h3>@ViewData["Message"]</h3>
  6. <p bold>Use this area to provide additional information.</p>
  7. <bold> Is this bold?</bold>
  • 运行应用。可以使用你喜爱的浏览器来检查源并验证标记。

上面的 [HtmlTargetElement] 属性仅针对提供属性名称“bold”的 HTML 标记。标记帮助程序未修改 <bold> 元素。

  • 标注出 [HtmlTargetElement] 属性行,它将默认为目标 <bold> 标记,也就是 <bold> 格式的 HTML 标记。请记住,默认的命名约定会将类名称 BoldTagHelper 与 标记相匹配<bold>

  • 运行应用并验证 <bold> 标记是否由标记帮助程序进行处理。

用多个 [HtmlTargetElement] 属性修饰类会导致目标出现逻辑 OR。例如,使用下面的代码时,系统将匹配出 bold 标记或 bold 属性。

  1. [HtmlTargetElement("bold")]
  2. [HtmlTargetElement(Attributes = "bold")]
  3. public class BoldTagHelper : TagHelper
  4. {
  5. public override void Process(TagHelperContext context, TagHelperOutput output)
  6. {
  7. output.Attributes.RemoveAll("bold");
  8. output.PreContent.SetHtmlContent("<strong>");
  9. output.PostContent.SetHtmlContent("</strong>");
  10. }
  11. }

将多个属性添加到同一语句时,运行时会将其视为逻辑 AND。例如,在下面的代码中,HTML 元素必须命名为“bold”并具有名为“bold”的属性 (<bold bold />) 才能匹配。

  1. [HtmlTargetElement("bold", Attributes = "bold")]

也可使用 [HtmlTargetElement] 更改目标元素的名称。例如,如果你希望 BoldTagHelper<MyBold> 标记为目标,则可使用以下属性:

  1. [HtmlTargetElement("MyBold")]

将模型传递到标记帮助程序Pass a model to a Tag Helper

  • 添加“Models”文件夹。

  • 将以下 WebsiteContext 类添加到“模型”文件夹:

  1. using System;
  2. namespace AuthoringTagHelpers.Models
  3. {
  4. public class WebsiteContext
  5. {
  6. public Version Version { get; set; }
  7. public int CopyrightYear { get; set; }
  8. public bool Approved { get; set; }
  9. public int TagsToShow { get; set; }
  10. }
  11. }
  • 将以下 WebsiteInformationTagHelper 类添加到“TagHelpers”文件夹。
  1. using System;
  2. using AuthoringTagHelpers.Models;
  3. using Microsoft.AspNetCore.Razor.TagHelpers;
  4. namespace AuthoringTagHelpers.TagHelpers
  5. {
  6. public class WebsiteInformationTagHelper : TagHelper
  7. {
  8. public WebsiteContext Info { get; set; }
  9. public override void Process(TagHelperContext context, TagHelperOutput output)
  10. {
  11. output.TagName = "section";
  12. output.Content.SetHtmlContent(
  13. $@"<ul><li><strong>Version:</strong> {Info.Version}</li>
  14. <li><strong>Copyright Year:</strong> {Info.CopyrightYear}</li>
  15. <li><strong>Approved:</strong> {Info.Approved}</li>
  16. <li><strong>Number of tags to show:</strong> {Info.TagsToShow}</li></ul>");
  17. output.TagMode = TagMode.StartTagAndEndTag;
  18. }
  19. }
  20. }
  • 如前所述,标记帮助程序会将标记帮助程序采用 Pascal 大小写格式的 C# 类名和属性转换为短横线格式。因此,要在 Razor 中使用 WebsiteInformationTagHelper,请编写 <website-information />

  • 未显式标识具有 [HtmlTargetElement] 属性的目标元素,因此 website-information 的默认值将成为目标元素。如果应用了以下属性(请注意,它虽不是短横线格式,但却与类名相匹配):

  1. [HtmlTargetElement("WebsiteInformation")]

短横线格式标记 <website-information /> 不匹配。若要使用 [HtmlTargetElement] 属性,请使用短横线格式,如下所示:

  1. [HtmlTargetElement("Website-Information")]
  • 自结束的元素没有任何内容。在此示例中,Razor 标记将使用自结束标记,但标记帮助程序将创建 section 元素(这不是自结束元素,并且你将在 section 元素中编写内容)。因此,需要将 TagMode 设置为 StartTagAndEndTag 以写入输出。或者,可以标注出行设置 TagMode 并用结束标记编写标记。(本教程后面将提供示例标记。)

  • 下一行中的 $(美元符号)使用内插字符串

  1. $@"<ul><li><strong>Version:</strong> {Info.Version}</li>
  • 将以下标记添加到 About.cshtml 视图。突出显示的标记显示 Web 站点信息。
  1. @using AuthoringTagHelpers.Models
  2. @{
  3. ViewData["Title"] = "About";
  4. WebsiteContext webContext = new WebsiteContext {
  5. Version = new Version(1, 3),
  6. CopyrightYear = 1638,
  7. Approved = true,
  8. TagsToShow = 131 };
  9. }
  10. <h2>@ViewData["Title"].</h2>
  11. <h3>@ViewData["Message"]</h3>
  12. <p bold>Use this area to provide additional information.</p>
  13. <bold> Is this bold?</bold>
  14. <h3> web site info </h3>
  15. <website-information info="webContext" />

备注

在 Razor 中,标记如下所示:

  1. <website-information info="webContext" />

Razor 知道 info 属性是一个类,而不是字符串,并且你想要编写 C# 代码。编写任何非字符串标记帮助程序属性时,都不应使用 @ 字符。

  • 运行应用,并导航到“关于”视图查看 Web 站点信息。

备注

可使用带有结束标记的以下标记,并在标记帮助程序中删除带有 TagMode.StartTagAndEndTag 的行:

  1. <website-information info="webContext" >
  2. </website-information>

条件标记帮助程序Condition Tag Helper

条件标记帮助程序在传递 true 值时呈现输出。

  • 将以下 ConditionTagHelper 类添加到“TagHelpers”文件夹。
  1. using Microsoft.AspNetCore.Razor.TagHelpers;
  2. namespace AuthoringTagHelpers.TagHelpers
  3. {
  4. [HtmlTargetElement(Attributes = nameof(Condition))]
  5. public class ConditionTagHelper : TagHelper
  6. {
  7. public bool Condition { get; set; }
  8. public override void Process(TagHelperContext context, TagHelperOutput output)
  9. {
  10. if (!Condition)
  11. {
  12. output.SuppressOutput();
  13. }
  14. }
  15. }
  16. }
  • 将 Views/Home/Index.cshtml 文件的内容替换为以下标记:
  1. @using AuthoringTagHelpers.Models
  2. @model WebsiteContext
  3. @{
  4. ViewData["Title"] = "Home Page";
  5. }
  6. <div>
  7. <h3>Information about our website (outdated):</h3>
  8. <Website-InforMation info="Model" />
  9. <div condition="Model.Approved">
  10. <p>
  11. This website has <strong surround="em">@Model.Approved</strong> been approved yet.
  12. Visit www.contoso.com for more information.
  13. </p>
  14. </div>
  15. </div>
  • Index 控制器中的 Home 方法替换为以下代码:
  1. public IActionResult Index(bool approved = false)
  2. {
  3. return View(new WebsiteContext
  4. {
  5. Approved = approved,
  6. CopyrightYear = 2015,
  7. Version = new Version(1, 3, 3, 7),
  8. TagsToShow = 20
  9. });
  10. }
  • 运行应用并浏览到主页。条件 div 中的标记不会呈现。将查询字符串 ?approved=true 追加到 URL(例如,http://localhost:1235/Home/Index?approved=true)。approved 设置为 true,并将显示条件标记。

备注

使用 nameof 运算符将属性指定为目标,而不是像使用 bold 标记帮助程序那样指定字符串:

  1. [HtmlTargetElement(Attributes = nameof(Condition))]
  2. // [HtmlTargetElement(Attributes = "condition")]
  3. public class ConditionTagHelper : TagHelper
  4. {
  5. public bool Condition { get; set; }
  6. public override void Process(TagHelperContext context, TagHelperOutput output)
  7. {
  8. if (!Condition)
  9. {
  10. output.SuppressOutput();
  11. }
  12. }
  13. }

如果代码被重构,nameof 运算符将保护它(可能需要将名称更改为 RedCondition)。

避免标记帮助程序冲突Avoid Tag Helper conflicts

在本部分中,你将编写一对自动链接标记帮助程序。第一个标记帮助程序会将包含以 HTTP 开头的 URL 的标记替换为包含相同 URL 的 HTML 定位标记(从而产生指向 URL 的链接)。第二个标记帮助程序也会对以 WWW 开头的 URL 执行相同的操作。

由于这两个帮助程序密切相关,并且你将来可能会重构它们,因此可将其保存在同一文件中。

  • 将以下 AutoLinkerHttpTagHelper 类添加到“TagHelpers”文件夹。
  1. [HtmlTargetElement("p")]
  2. public class AutoLinkerHttpTagHelper : TagHelper
  3. {
  4. public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
  5. {
  6. var childContent = await output.GetChildContentAsync();
  7. // Find Urls in the content and replace them with their anchor tag equivalent.
  8. output.Content.SetHtmlContent(Regex.Replace(
  9. childContent.GetContent(),
  10. @"\b(?:https?://)(\S+)\b",
  11. "<a target=\"_blank\" href=\"$0\">$0</a>")); // http link version}
  12. }
  13. }

备注

AutoLinkerHttpTagHelper 类以 p 元 素为目标,并使用正则表达式来创建定位点。

  • 将以下标记添加到 Views/Home/Contact.cshtml 文件的末尾:
  1. @{
  2. ViewData["Title"] = "Contact";
  3. }
  4. <h2>@ViewData["Title"].</h2>
  5. <h3>@ViewData["Message"]</h3>
  6. <address>
  7. One Microsoft Way<br />
  8. Redmond, WA 98052<br />
  9. <abbr title="Phone">P:</abbr>
  10. 425.555.0100
  11. </address>
  12. <address>
  13. <strong>Support:</strong><email>Support</email><br />
  14. <strong>Marketing:</strong><email>Marketing</email>
  15. </address>
  16. <p>Visit us at http://docs.asp.net or at www.microsoft.com</p>
  • 运行应用并验证标记帮助程序是否正确呈现定位点。

  • 更新 AutoLinker 类以包含 AutoLinkerWwwTagHelper,这会将 www 文本转换为还包含原始 www 文本的定位标记。更新后的代码在下方突出显示:

  1. [HtmlTargetElement("p")]
  2. public class AutoLinkerHttpTagHelper : TagHelper
  3. {
  4. public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
  5. {
  6. var childContent = await output.GetChildContentAsync();
  7. // Find Urls in the content and replace them with their anchor tag equivalent.
  8. output.Content.SetHtmlContent(Regex.Replace(
  9. childContent.GetContent(),
  10. @"\b(?:https?://)(\S+)\b",
  11. "<a target=\"_blank\" href=\"$0\">$0</a>")); // http link version}
  12. }
  13. }
  14. [HtmlTargetElement("p")]
  15. public class AutoLinkerWwwTagHelper : TagHelper
  16. {
  17. public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
  18. {
  19. var childContent = await output.GetChildContentAsync();
  20. // Find Urls in the content and replace them with their anchor tag equivalent.
  21. output.Content.SetHtmlContent(Regex.Replace(
  22. childContent.GetContent(),
  23. @"\b(www\.)(\S+)\b",
  24. "<a target=\"_blank\" href=\"http://$0\">$0</a>")); // www version
  25. }
  26. }
  27. }
  • 运行应用。请注意 www 文本呈现为链接,但 HTTP 文本不是。如果将中断点放在这两个类中,可以看到 HTTP 标记帮助程序类首先运行。问题是,标记帮助程序输出已缓存,当运行 WWW 标记帮助程序时,它会覆盖 HTTP 标记帮助程序的缓存输出。本教程稍后将介绍如何控制标记帮助程序中的运行顺序。我们将用以下方法修复代码:
  1. public class AutoLinkerHttpTagHelper : TagHelper
  2. {
  3. public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
  4. {
  5. var childContent = output.Content.IsModified ? output.Content.GetContent() :
  6. (await output.GetChildContentAsync()).GetContent();
  7. // Find Urls in the content and replace them with their anchor tag equivalent.
  8. output.Content.SetHtmlContent(Regex.Replace(
  9. childContent,
  10. @"\b(?:https?://)(\S+)\b",
  11. "<a target=\"_blank\" href=\"$0\">$0</a>")); // http link version}
  12. }
  13. }
  14. [HtmlTargetElement("p")]
  15. public class AutoLinkerWwwTagHelper : TagHelper
  16. {
  17. public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
  18. {
  19. var childContent = output.Content.IsModified ? output.Content.GetContent() :
  20. (await output.GetChildContentAsync()).GetContent();
  21. // Find Urls in the content and replace them with their anchor tag equivalent.
  22. output.Content.SetHtmlContent(Regex.Replace(
  23. childContent,
  24. @"\b(www\.)(\S+)\b",
  25. "<a target=\"_blank\" href=\"http://$0\">$0</a>")); // www version
  26. }
  27. }

备注

在自动链接标记帮助程序的第一版中,使用以下代码获取了目标的内容:

  1. var childContent = await output.GetChildContentAsync();

也就是说,使用传递到 GetChildContentAsync 方法的 TagHelperOutput 调用 ProcessAsync。如前所述,由于输出已缓存,因此将调用最后运行的标记帮助程序。使用以下代码解决了这个问题:

  1. var childContent = output.Content.IsModified ? output.Content.GetContent() :
  2. (await output.GetChildContentAsync()).GetContent();

上面的代码检查内容是否已修改,如果已修改,则从输出缓冲区获取内容。

  • 运行应用并验证这两个链接是否按预期工作。虽然它可能显示自动链接器标记帮助程序是正确且完整的,但它有一个细微的问题。如果首先运行 WWW 标记帮助程序,则 www 链接不正确。通过添加 Order 重载更新代码来控制标记运行的顺序。Order 属性确定相对于面向同一元素的其他标记帮助程序的执行顺序。默认顺序值为零,并首先执行具有较低值的实例。
  1. public class AutoLinkerHttpTagHelper : TagHelper
  2. {
  3. // This filter must run before the AutoLinkerWwwTagHelper as it searches and replaces http and
  4. // the AutoLinkerWwwTagHelper adds http to the markup.
  5. public override int Order
  6. {
  7. get { return int.MinValue; }
  8. }

上面的代码可以保证 HTTP 标记帮助程序在 WWW 标记帮助程序之前运行。将 Order 更改为 MaxValue 并验证为 WWW 标记生成的标记是否不正确。

检查和检索子内容Inspect and retrieve child content

标记帮助程序提供多个属性来检索内容。

  • 可将 GetChildContentAsync 的结果追加到 output.Content
  • 可使用 GetChildContentAsync 检查 GetContent 的结果。
  • 如果修改 output.Content,则不会执行或呈现 TagHelper 主体,除非像自动链接器示例中那样调用 GetChildContentAsync
  1. public class AutoLinkerHttpTagHelper : TagHelper
  2. {
  3. public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
  4. {
  5. var childContent = output.Content.IsModified ? output.Content.GetContent() :
  6. (await output.GetChildContentAsync()).GetContent();
  7. // Find Urls in the content and replace them with their anchor tag equivalent.
  8. output.Content.SetHtmlContent(Regex.Replace(
  9. childContent,
  10. @"\b(?:https?://)(\S+)\b",
  11. "<a target=\"_blank\" href=\"$0\">$0</a>")); // http link version}
  12. }
  13. }
  • GetChildContentAsync 的多次调用返回相同的值,且不重新执行 TagHelper 主体,除非传入一个指示不使用缓存结果的 false 参数。

加载缩小的分部视图 TagHelperLoad minified partial view TagHelper

在生产环境中,可以通过加载缩小的分部视图来提升性能。若要在生产环境中利用缩小的分部视图,请执行以下操作:

  • 创建/设置缩小分部视图的预生成过程。
  • 使用以下代码在非开发环境中加载缩小的分部视图。
public class MinifiedVersionPartialTagHelper : PartialTagHelper
    {
        public MinifiedVersionPartialTagHelper(ICompositeViewEngine viewEngine, 
                                IViewBufferScope viewBufferScope)
                               : base(viewEngine, viewBufferScope)
        {

        }

        public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            // Append ".min" to load the minified partial view.
            if (!IsDevelopment())
            {
                Name += ".min";
            }

            return base.ProcessAsync(context, output);
        }

        private bool IsDevelopment()
        {
            return Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") 
                                                 == EnvironmentName.Development;
        }
    }