Nguon: Microsoft Learn · .NET 8.0

Tạo Tag Helpers (Trình trợ giúp thẻ) trong ASP.NET Core

Nguồn: Author Tag Helpers in ASP.NET Core

Bởi Rick Anderson

Xem hoặc tải xuống mã mẫu (cách tải xuống)

Bắt đầu với Tag Helpers

Hướng dẫn này cung cấp phần giới thiệu lập trình Tag Helpers. Giới thiệu về Tag Helpers mô tả các lợi ích mà Tag Helpers cung cấp.

Một tag helper là bất kỳ lớp nào implement (cài đặt) interface ITagHelper. Tuy nhiên, khi bạn tạo một tag helper, bạn thường kế thừa từ TagHelper, làm như vậy cho phép bạn truy cập vào method Process.

  1. Tạo một dự án ASP.NET Core mới gọi là AuthoringTagHelpers. Bạn sẽ không cần xác thực cho dự án này.
  2. Tạo một thư mục để chứa Tag Helpers gọi là TagHelpers. Thư mục TagHelpers không bắt buộc, nhưng đây là một quy ước hợp lý.

Một Tag Helper tối giản

Trong phần này, bạn viết một tag helper cập nhật thẻ email. Ví dụ:

html
<email>Support</email>

Server sẽ sử dụng email tag helper để chuyển đổi markup đó thành:

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

Đó là, một thẻ anchor (neo) làm cho email này thành một email link. Bạn có thể muốn làm điều này nếu bạn đang viết một blog engine và cần nó gửi email cho marketing, hỗ trợ, và các liên hệ khác, tất cả đến cùng một domain.

  1. Thêm lớp EmailTagHelper sau vào thư mục TagHelpers.

```csharp

using Microsoft.AspNetCore.Razor.TagHelpers; using System.Threading.Tasks;

namespace AuthoringTagHelpers.TagHelpers { public class EmailTagHelper : TagHelper { public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "a"; // Replaces <email> with <a> tag } } } ```

  1. Để làm cho lớp EmailTagHelper có sẵn cho tất cả Razor views, thêm directive addTagHelper vào file Views/_ViewImports.cshtml:

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

  1. Cập nhật markup trong file Views/Home/Contact.cshtml với các thay đổi sau:

```cshtml @{ ViewData["Title"] = "Contact"; } <h2>@ViewData["Title"].</h2> <h3>@ViewData["Message"]</h3>

<address> One Microsoft Way<br /> Redmond, WA 98052<br /> <abbr title="Phone">P:</abbr> 425.555.0100 </address>

<address> <strong>Support:</strong><email>Support</email><br /> <strong>Marketing:</strong><email>Marketing</email> </address> ```

  1. Chạy ứng dụng và sử dụng trình duyệt để xem source HTML để xác minh rằng các thẻ email được thay thế bằng anchor markup (Ví dụ: <a>Support</a>).

SetAttribute và SetContent

Trong phần này, chúng ta sẽ cập nhật EmailTagHelper để nó tạo ra một thẻ anchor hợp lệ cho email. Chúng ta sẽ cập nhật nó để lấy thông tin từ Razor view (dưới dạng thuộc tính mail-to) và sử dụng nó trong việc tạo anchor.

Cập nhật lớp EmailTagHelper với đoạn code sau:

csharp
public class EmailTagHelper : TagHelper
{
    private const string EmailDomain = "contoso.com";

    // Can be passed via <email mail-to="..." />. 
    // PascalCase gets translated into kebab-case.
    public string MailTo { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "a";    // Replaces <email> with <a> tag

        var address = MailTo + "@" + EmailDomain;
        output.Attributes.SetAttribute("href", "mailto:" + address);
        output.Content.SetContent(address);
    }
}
  1. Cập nhật markup trong file Views/Home/Contact.cshtml với các thay đổi sau:

```cshtml @{ ViewData["Title"] = "Contact Copy"; } <h2>@ViewData["Title"].</h2> <h3>@ViewData["Message"]</h3>

<address> One Microsoft Way Copy Version <br /> Redmond, WA 98052-6399<br /> <abbr title="Phone">P:</abbr> 425.555.0100 </address>

<address> <strong>Support:</strong><email mail-to="Support"></email><br /> <strong>Marketing:</strong><email mail-to="Marketing"></email> </address> ```

  1. Chạy ứng dụng và xác minh rằng nó tạo ra các links chính xác.

Nếu bạn viết email tag self-closing (<email mail-to="Rick" />), output cuối cùng cũng sẽ là self-closing. Để kích hoạt khả năng viết thẻ chỉ với thẻ bắt đầu (<email mail-to="Rick">), bạn phải đánh dấu lớp với:

``csharp [HtmlTargetElement("email", TagStructure = TagStructure.WithoutEndTag)] public class EmailVoidTagHelper : TagHelper ``

Bạn cũng có thể ánh xạ một tên thuộc tính khác vào một property bằng cách sử dụng thuộc tính [HtmlAttributeName]:

csharp
[HtmlAttributeName("recipient")]
public string? MailTo { get; set; }

Tag Helper cho thuộc tính recipient:

html
<email recipient="…"/>

ProcessAsync

Trong phần này, chúng ta sẽ viết một email helper bất đồng bộ.

  1. Thay thế lớp EmailTagHelper bằng code sau:

``csharp public class EmailTagHelper : TagHelper { private const string EmailDomain = "contoso.com"; public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { output.TagName = "a"; // Replaces <email> with <a> tag var content = await output.GetChildContentAsync(); var target = content.GetContent() + "@" + EmailDomain; output.Attributes.SetAttribute("href", "mailto:" + target); output.Content.SetContent(target); } } ``

Lưu ý:

RemoveAll, PreContent.SetHtmlContent và PostContent.SetHtmlContent

  1. Thêm lớp BoldTagHelper sau vào thư mục TagHelpers:

```csharp using Microsoft.AspNetCore.Razor.TagHelpers;

namespace AuthoringTagHelpers.TagHelpers { [HtmlTargetElement(Attributes = "bold")] public class BoldTagHelper : TagHelper { public override void Process(TagHelperContext context, TagHelperOutput output) { output.Attributes.RemoveAll("bold"); output.PreContent.SetHtmlContent("<strong>"); output.PostContent.SetHtmlContent("</strong>"); } } } ```

Truyền một model vào Tag Helper

  1. Thêm lớp WebsiteInformationTagHelper vào thư mục TagHelpers:

```csharp using System; using AuthoringTagHelpers.Models; using Microsoft.AspNetCore.Razor.TagHelpers;

namespace AuthoringTagHelpers.TagHelpers { public class WebsiteInformationTagHelper : TagHelper { public WebsiteContext Info { get; set; }

public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "section"; output.Content.SetHtmlContent( $@"<ul><li><strong>Version:</strong> {Info.Version}</li> <li><strong>Copyright Year:</strong> {Info.CopyrightYear}</li> <li><strong>Approved:</strong> {Info.Approved}</li> <li><strong>Number of tags to show:</strong> {Info.TagsToShow}</li></ul>"); output.TagMode = TagMode.StartTagAndEndTag; } } } ```

Condition Tag Helper (Tag Helper điều kiện)

Condition tag helper render output khi được truyền giá trị true.

  1. Thêm lớp ConditionTagHelper sau vào thư mục TagHelpers:

```csharp using Microsoft.AspNetCore.Razor.TagHelpers;

namespace AuthoringTagHelpers.TagHelpers { [HtmlTargetElement(Attributes = nameof(Condition))] public class ConditionTagHelper : TagHelper { public bool Condition { get; set; }

public override void Process(TagHelperContext context, TagHelperOutput output) { if (!Condition) { output.SuppressOutput(); } } } } ```

  1. Thay thế nội dung của file Views/Home/Index.cshtml bằng markup sau:

```cshtml @using AuthoringTagHelpers.Models @model WebsiteContext

@{ ViewData["Title"] = "Home Page"; }

<div> <h3>Information about our website (outdated):</h3> <Website-InforMation info="Model" /> <div condition="Model.Approved"> <p> This website has <strong surround="em">@Model.Approved</strong> been approved yet. Visit www.contoso.com for more information. </p> </div> </div> ```

  1. Thay thế method Index trong controller Home bằng code sau:

``csharp public IActionResult Index(bool approved = false) { return View(new WebsiteContext { Approved = approved, CopyrightYear = 2015, Version = new Version(1, 3, 3, 7), TagsToShow = 20 }); } ``

  1. Chạy ứng dụng và điều hướng đến trang home. Markup trong div điều kiện sẽ không được render. Thêm query string ?approved=true vào URL (ví dụ: http://localhost:1235/Home/Index?approved=true). approved được đặt thành true và markup điều kiện sẽ được hiển thị.

Sử dụng toán tử nameof để chỉ định thuộc tính cần target thay vì chỉ định một chuỗi như bạn đã làm với bold tag helper:

``csharp [HtmlTargetElement(Attributes = nameof(Condition))] ``

Toán tử nameof sẽ bảo vệ code nếu nó được refactor (tái cấu trúc) sau này.

Tránh xung đột Tag Helper

Trong phần này, bạn viết một cặp auto-linking tag helpers. Cái đầu tiên sẽ thay thế markup chứa URL bắt đầu bằng HTTP thành thẻ anchor HTML chứa cùng URL. Cái thứ hai sẽ làm tương tự cho URL bắt đầu bằng WWW.

  1. Thêm lớp AutoLinkerHttpTagHelper sau vào thư mục TagHelpers:

``csharp [HtmlTargetElement("p")] public class AutoLinkerHttpTagHelper : TagHelper { public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { var childContent = await output.GetChildContentAsync(); // Find Urls in the content and replace them with their anchor tag equivalent. output.Content.SetHtmlContent(Regex.Replace( childContent.GetContent(), @"\b(?:https?://)(\S+)\b", "<a target=\"_blank\" href=\"$0\">$0</a>")); // http link version} } } ``

  1. Thêm lớp AutoLinkerWwwTagHelper để chuyển đổi text www thành thẻ anchor:

```csharp [HtmlTargetElement("p")] public class AutoLinkerWwwTagHelper : TagHelper { public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { var childContent = output.Content.IsModified ? output.Content.GetContent() : (await output.GetChildContentAsync()).GetContent();

// Find Urls in the content and replace them with their anchor tag equivalent. output.Content.SetHtmlContent(Regex.Replace( childContent, @"\b(www\.)(\S+)\b", "<a target=\"_blank\" href=\"http://$0\">$0</a>")); // www version } } ```

  1. Để kiểm soát thứ tự thực thi tag helper, sử dụng thuộc tính Order. Thuộc tính Order xác định thứ tự thực thi liên quan đến các tag helper khác targeting cùng phần tử. Giá trị order mặc định là zero và các instance có giá trị thấp hơn được thực thi trước.

``csharp public class AutoLinkerHttpTagHelper : TagHelper { // This filter must run before the AutoLinkerWwwTagHelper as it searches and replaces http and // the AutoLinkerWwwTagHelper adds http to the markup. public override int Order { get { return int.MinValue; } } ``

Kiểm tra và lấy nội dung con

Tag helpers cung cấp một số properties để lấy nội dung.

csharp
public class AutoLinkerHttpTagHelper : TagHelper
{
    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        var childContent = output.Content.IsModified ? output.Content.GetContent() :
            (await output.GetChildContentAsync()).GetContent();

        // Find Urls in the content and replace them with their anchor tag equivalent.
        output.Content.SetHtmlContent(Regex.Replace(
             childContent,
             @"\b(?:https?://)(\S+)\b",
              "<a target=\"_blank\" href=\"$0\">$0</a>"));  // http link version}
    }
}

Tải minified partial view TagHelper

Trong môi trường production, hiệu suất có thể được cải thiện bằng cách tải các minified partial views. Để tận dụng minified partial view trong production:

csharp
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;
        }
    }