ASP.NET Core 中的标记帮助程序组件Tag Helper Components in ASP.NET Core

本文内容

作者:Scott AddieFiyaz Bin Hasan

标记帮助程序组件是可用于有条件地修改或添加服务器端代码中的 HTML 元素的标记帮助程序。ASP.NET Core 2.0 或更高版本中提供了此功能。

ASP.NET Core 包括两个内置标记帮助程序组件:headbody它们位于 Microsoft.AspNetCore.Mvc.Razor.TagHelpers 命名空间中,可用于 MVC 和 Razor Pages。标记帮助程序组件不需要在 _ViewImports.cshtml 中注册应用。

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

用例Use cases

标记帮助程序组件的两个常见用例包括:

注入到 HTML head 元素中Inject into HTML head element

在 HTML <head> 元素中,通常使用 HTML <link> 元素导入 CSS 文件。以下代码使用 <link> 标记帮助程序组件将 <head> 元素注入到 head 元素中:

  1. using System;
  2. using System.Threading.Tasks;
  3. using Microsoft.AspNetCore.Razor.TagHelpers;
  4. namespace RazorPagesSample.TagHelpers
  5. {
  6. public class AddressStyleTagHelperComponent : TagHelperComponent
  7. {
  8. private readonly string _style =
  9. @"<link rel=""stylesheet"" href=""/css/address.css"" />";
  10. public override int Order => 1;
  11. public override Task ProcessAsync(TagHelperContext context,
  12. TagHelperOutput output)
  13. {
  14. if (string.Equals(context.TagName, "head",
  15. StringComparison.OrdinalIgnoreCase))
  16. {
  17. output.PostContent.AppendHtml(_style);
  18. }
  19. return Task.CompletedTask;
  20. }
  21. }
  22. }

在上述代码中:

  • AddressStyleTagHelperComponent 可实现 TagHelperComponent。抽象:
    • 允许初始化带有 TagHelperContext 的类。
    • 启用标记帮助程序组件以添加或修改 HTML 元素。
  • Order 属性可定义呈现组件的顺序。应用中的标记帮助程序组件有多种用法时,Order 是必需的。
  • ProcessAsync 会将执行上下文的 TagName 属性值与 head 进行比较。如果比较的计算结果为 true,则 _style 字段的内容将注入到 HTML <head> 元素中。

注入到 HTML body 元素中Inject into HTML body element

body 标记帮助程序组件可以将 <script> 元素注入到 <body> 元素中。以下代码演示了此项技术:

  1. using System;
  2. using System.IO;
  3. using System.Threading.Tasks;
  4. using Microsoft.AspNetCore.Razor.TagHelpers;
  5. namespace RazorPagesSample.TagHelpers
  6. {
  7. public class AddressScriptTagHelperComponent : TagHelperComponent
  8. {
  9. public override int Order => 2;
  10. public override async Task ProcessAsync(TagHelperContext context,
  11. TagHelperOutput output)
  12. {
  13. if (string.Equals(context.TagName, "body",
  14. StringComparison.OrdinalIgnoreCase))
  15. {
  16. var script = await File.ReadAllTextAsync(
  17. "TagHelpers/Templates/AddressToolTipScript.html");
  18. output.PostContent.AppendHtml(script);
  19. }
  20. }
  21. }
  22. }

单独的 HTML 文件用于存储 <script> 元素。HTML 文件使代码更清洁且更易于维护。上述代码可读取 TagHelpers/Templates/AddressToolTipScript.html 的内容并将其追加到标记帮助程序输出中。AddressToolTipScript.html 文件包括以下标记:

  1. <script>
  2. $("address[printable]").hover(function() {
  3. $(this).attr({
  4. "data-toggle": "tooltip",
  5. "data-placement": "right",
  6. "title": "Home of Microsoft!"
  7. });
  8. });
  9. </script>

上述代码可将启动工具提示小组件绑定到包含 <address> 属性的任何 printable 元素。当鼠标指针悬停在元素上时,可以显示效果。

注册组件Register a Component

标记帮助程序组件必须添加到应用的标记帮助程序组件集合。有以下三种方法可添加到集合:

通过服务容器注册Registration via services container

如果未使用 ITagHelperComponentManager 管理标记帮助程序组件类,则必须向依赖关系注入 (DI) 系统注册。以下 Startup.ConfigureServices 代码可注册带有AddressStyleTagHelperComponent瞬态生存期AddressScriptTagHelperComponent 类:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.Configure<CookiePolicyOptions>(options =>
  4. {
  5. options.CheckConsentNeeded = context => true;
  6. options.MinimumSameSitePolicy = SameSiteMode.None;
  7. });
  8. services.AddMvc()
  9. .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
  10. services.AddTransient<ITagHelperComponent,
  11. AddressScriptTagHelperComponent>();
  12. services.AddTransient<ITagHelperComponent,
  13. AddressStyleTagHelperComponent>();
  14. }

通过 Razor 文件注册Registration via Razor file

如果未向 DI 注册标记帮助程序组件,则可以从 Razor Pages 页或 MVC 视图注册。此项技术用于控制注入的标记和 Razor 文件中的组件执行顺序。

ITagHelperComponentManager 用于添加标记帮助程序组件或从应用中删除这些组件。以下代码演示了使用 AddressTagHelperComponent 的此项技术:

  1. @using RazorPagesSample.TagHelpers;
  2. @using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
  3. @inject ITagHelperComponentManager manager;
  4. @{
  5. string markup;
  6. if (Model.IsWeekend)
  7. {
  8. markup = "<em class='text-warning'>Office closed today!</em>";
  9. }
  10. else
  11. {
  12. markup = "<em class='text-info'>Office open today!</em>";
  13. }
  14. manager.Components.Add(new AddressTagHelperComponent(markup, 1));
  15. }

在上述代码中:

  • @inject 指令提供了 ITagHelperComponentManager 的实例。该实例将分配到名为 manager 的变量以访问 Razor 文件中的下游。
  • AddressTagHelperComponent 的实例将添加到应用的标记帮助程序组件集合。

修改 AddressTagHelperComponent 以适应接受 markuporder 参数的构造函数:

  1. private readonly string _markup;
  2. public override int Order { get; }
  3. public AddressTagHelperComponent(string markup = "", int order = 1)
  4. {
  5. _markup = markup;
  6. Order = order;
  7. }

提供的 markup 参数用于 ProcessAsync,如下所示:

  1. public override async Task ProcessAsync(TagHelperContext context,
  2. TagHelperOutput output)
  3. {
  4. if (string.Equals(context.TagName, "address",
  5. StringComparison.OrdinalIgnoreCase) &&
  6. output.Attributes.ContainsName("printable"))
  7. {
  8. TagHelperContent childContent = await output.GetChildContentAsync();
  9. string content = childContent.GetContent();
  10. output.Content.SetHtmlContent(
  11. $"<div>{content}<br>{_markup}</div>{_printableButton}");
  12. }
  13. }

通过页面模型或控制器注册Registration via Page Model or controller

如果未向 DI 注册标记帮助程序组件,则可以从 Razor Pages 页面模型或 MVC 控制器注册。此项技术可用于将 C# 逻辑与 Razor 文件隔离。

构造函数注入用于访问 ITagHelperComponentManager 的实例。标记帮助程序组件将添加到该实例的标记帮助程序组件集合。以下 Razor Pages 页面模型演示了使用 AddressTagHelperComponent 的此项技术:

  1. using System;
  2. using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
  3. using Microsoft.AspNetCore.Mvc.RazorPages;
  4. using RazorPagesSample.TagHelpers;
  5. public class IndexModel : PageModel
  6. {
  7. private readonly ITagHelperComponentManager _tagHelperComponentManager;
  8. public bool IsWeekend
  9. {
  10. get
  11. {
  12. var dayOfWeek = DateTime.Now.DayOfWeek;
  13. return dayOfWeek == DayOfWeek.Saturday ||
  14. dayOfWeek == DayOfWeek.Sunday;
  15. }
  16. }
  17. public IndexModel(ITagHelperComponentManager tagHelperComponentManager)
  18. {
  19. _tagHelperComponentManager = tagHelperComponentManager;
  20. }
  21. public void OnGet()
  22. {
  23. string markup;
  24. if (IsWeekend)
  25. {
  26. markup = "<em class='text-warning'>Office closed today!</em>";
  27. }
  28. else
  29. {
  30. markup = "<em class='text-info'>Office open today!</em>";
  31. }
  32. _tagHelperComponentManager.Components.Add(
  33. new AddressTagHelperComponent(markup, 1));
  34. }
  35. }

在上述代码中:

  • 构造函数注入用于访问 ITagHelperComponentManager 的实例。
  • AddressTagHelperComponent 的实例将添加到应用的标记帮助程序组件集合。

创建组件Create a Component

创建自定义标记帮助程序组件:

以下代码可创建面向 <address> HTML 元素的自定义标记帮助程序组件:

  1. using System.ComponentModel;
  2. using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
  3. using Microsoft.AspNetCore.Razor.TagHelpers;
  4. using Microsoft.Extensions.Logging;
  5. namespace RazorPagesSample.TagHelpers
  6. {
  7. [HtmlTargetElement("address")]
  8. [EditorBrowsable(EditorBrowsableState.Never)]
  9. public class AddressTagHelperComponentTagHelper : TagHelperComponentTagHelper
  10. {
  11. public AddressTagHelperComponentTagHelper(
  12. ITagHelperComponentManager componentManager,
  13. ILoggerFactory loggerFactory) : base(componentManager, loggerFactory)
  14. {
  15. }
  16. }
  17. }

按如下所示使用自定义 address 标记帮助程序组件注入 HTML 标记:

  1. public class AddressTagHelperComponent : TagHelperComponent
  2. {
  3. private readonly string _printableButton =
  4. "<button type='button' class='btn btn-info' onclick=\"window.open(" +
  5. "'https://binged.it/2AXRRYw')\">" +
  6. "<span class='glyphicon glyphicon-road' aria-hidden='true'></span>" +
  7. "</button>";
  8. public override int Order => 3;
  9. public override async Task ProcessAsync(TagHelperContext context,
  10. TagHelperOutput output)
  11. {
  12. if (string.Equals(context.TagName, "address",
  13. StringComparison.OrdinalIgnoreCase) &&
  14. output.Attributes.ContainsName("printable"))
  15. {
  16. var content = await output.GetChildContentAsync();
  17. output.Content.SetHtmlContent(
  18. $"<div>{content.GetContent()}</div>{_printableButton}");
  19. }
  20. }
  21. }

上述 ProcessAsync 方法可将向 SetHtmlContent 提供的 HTML 注入到匹配的 <address> 元素中。在以下情况下进行注入:

  • 执行上下文的 TagName 属性值等于 address
  • 相应的 <address> 元素具有 printable 属性。

例如,在处理以下 if 元素时,<address> 语句的计算结果为 true:

  1. <address printable>
  2. One Microsoft Way<br />
  3. Redmond, WA 98052-6399<br />
  4. <abbr title="Phone">P:</abbr>
  5. 425.555.0100
  6. </address>

其他资源Additional resources