Nguon: Microsoft Learn · .NET 8.0

Tag Helper Components trong ASP.NET Core

Nguồn: Tag Helper Components in ASP.NET Core

Bởi Scott AddieFiyaz Bin Hasan

Tag Helper Component (thành phần Tag Helper) là một Tag Helper cho phép bạn có điều kiện sửa đổi hoặc thêm các phần tử HTML từ server-side code. Tính năng này có sẵn trong ASP.NET Core 2.0 trở lên.

ASP.NET Core bao gồm hai Tag Helper Components tích hợp sẵn: headbody. Chúng nằm trong namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers và có thể được sử dụng trong cả MVC lẫn Razor Pages. Tag Helper Components không cần đăng ký với ứng dụng trong _ViewImports.cshtml.

Xem hoặc tải xuống mã mẫu

Các trường hợp sử dụng

Hai trường hợp sử dụng phổ biến của Tag Helper Components bao gồm:

  1. Inject (chèn) một <link> vào <head>.
  2. Inject một <script> vào <body>.

Các phần sau mô tả những trường hợp sử dụng này.

Inject vào phần tử HTML head

Bên trong phần tử HTML <head>, các file CSS thường được import bằng phần tử HTML <link>. Code sau inject một phần tử <link> vào phần tử <head> bằng cách dùng Tag Helper Component head:

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

namespace RazorPagesSample.TagHelpers
{
    public class AddressStyleTagHelperComponent : TagHelperComponent
    {
        private readonly string _style = 
            @"<link rel=""stylesheet"" href=""/css/address.css"" />";

        public override int Order => 1;

        public override Task ProcessAsync(TagHelperContext context,
                                          TagHelperOutput output)
        {
            if (string.Equals(context.TagName, "head", 
                              StringComparison.OrdinalIgnoreCase))
            {
                output.PostContent.AppendHtml(_style);
            }

            return Task.CompletedTask;
        }
    }
}

Trong code trên:

Inject vào phần tử HTML body

Tag Helper Component body có thể inject một phần tử <script> vào phần tử <body>. Code sau minh họa kỹ thuật này:

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

namespace RazorPagesSample.TagHelpers
{
    public class AddressScriptTagHelperComponent : TagHelperComponent
    {
        public override int Order => 2;
        
        public override async Task ProcessAsync(TagHelperContext context,
                                                TagHelperOutput output)
        {
            if (string.Equals(context.TagName, "body",
                              StringComparison.OrdinalIgnoreCase))
            {
                var script = await File.ReadAllTextAsync(
                    "TagHelpers/Templates/AddressToolTipScript.html");
                output.PostContent.AppendHtml(script);
            }
        }
    }
}

Một file HTML riêng được dùng để lưu trữ phần tử <script>. File HTML làm code sạch hơn và dễ bảo trì hơn. Code trên đọc nội dung của TagHelpers/Templates/AddressToolTipScript.html và append nó với Tag Helper output. File AddressToolTipScript.html bao gồm markup sau:

html
<script>
$("address[printable]").hover(function() {
    $(this).attr({
        "data-toggle": "tooltip",
        "data-placement": "right",
        "title": "Home of Microsoft!"
    });
});
</script>

Code trên liên kết một Bootstrap tooltip widget với bất kỳ phần tử <address> nào bao gồm thuộc tính printable. Hiệu ứng hiển thị khi con trỏ chuột di chuyển qua phần tử.

Đăng ký Component

Tag Helper Component phải được thêm vào collection Tag Helper Components của ứng dụng. Có ba cách để thêm vào collection:

Đăng ký qua services container

Nếu class Tag Helper Component không được quản lý bởi ITagHelperComponentManager, nó phải được đăng ký với hệ thống dependency injection (DI). Code Startup.ConfigureServices sau đăng ký các class AddressStyleTagHelperComponentAddressScriptTagHelperComponent với transient lifetime (vòng đời tạm thời):

csharp
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.AddTransient<ITagHelperComponent, 
        AddressScriptTagHelperComponent>();
    services.AddTransient<ITagHelperComponent, 
        AddressStyleTagHelperComponent>();
}

Đăng ký qua Razor file

Nếu Tag Helper Component không được đăng ký với DI, nó có thể được đăng ký từ Razor Pages page hoặc MVC view. Kỹ thuật này được sử dụng để kiểm soát markup được inject và thứ tự thực thi component từ Razor file.

ITagHelperComponentManager được dùng để thêm Tag Helper Components hoặc xóa chúng khỏi ứng dụng. Code sau minh họa kỹ thuật này với AddressTagHelperComponent:

cshtml
@using RazorPagesSample.TagHelpers;
@using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
@inject ITagHelperComponentManager manager;

@{
    string markup;

    if (Model.IsWeekend)
    {
        markup = "<em class='text-warning'>Office closed today!</em>";
    }
    else
    {
        markup = "<em class='text-info'>Office open today!</em>";
    }

    manager.Components.Add(new AddressTagHelperComponent(markup, 1));
}

Trong code trên:

AddressTagHelperComponent được sửa đổi để chấp nhận constructor nhận tham số markuporder:

csharp
private readonly string _markup;

public override int Order { get; }

public AddressTagHelperComponent(string markup = "", int order = 1)
{
    _markup = markup;
    Order = order;
}

Tham số markup được cung cấp được sử dụng trong ProcessAsync như sau:

csharp
public override async Task ProcessAsync(TagHelperContext context,
                                        TagHelperOutput output)
{
    if (string.Equals(context.TagName, "address",
            StringComparison.OrdinalIgnoreCase) &&
        output.Attributes.ContainsName("printable"))
    {
        TagHelperContent childContent = await output.GetChildContentAsync();
        string content = childContent.GetContent();
        output.Content.SetHtmlContent(
            $"<div>{content}<br>{_markup}</div>{_printableButton}");
    }
}

Đăng ký qua Page Model hoặc controller

Nếu Tag Helper Component không được đăng ký với DI, nó có thể được đăng ký từ Razor Pages page model hoặc MVC controller. Kỹ thuật này hữu ích để tách biệt logic C# khỏi Razor files.

Constructor injection được sử dụng để truy cập một instance của ITagHelperComponentManager. Tag Helper Component được thêm vào collection Tag Helper Components của instance. Razor Pages page model sau minh họa kỹ thuật này với AddressTagHelperComponent:

csharp
using System;
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesSample.TagHelpers;

public class IndexModel : PageModel
{
    private readonly ITagHelperComponentManager _tagHelperComponentManager;

    public bool IsWeekend
    {
        get
        {
            var dayOfWeek = DateTime.Now.DayOfWeek;

            return dayOfWeek == DayOfWeek.Saturday ||
                   dayOfWeek == DayOfWeek.Sunday;
        }
    }

    public IndexModel(ITagHelperComponentManager tagHelperComponentManager)
    {
        _tagHelperComponentManager = tagHelperComponentManager;
    }

    public void OnGet()
    {
        string markup;

        if (IsWeekend)
        {
            markup = "<em class='text-warning'>Office closed today!</em>";
        }
        else
        {
            markup = "<em class='text-info'>Office open today!</em>";
        }

        _tagHelperComponentManager.Components.Add(
            new AddressTagHelperComponent(markup, 1));
    }
}

Trong code trên:

Tạo Component

Để tạo Tag Helper Component tùy chỉnh:

Code sau tạo Tag Helper Component tùy chỉnh nhắm đến phần tử HTML <address>:

csharp
using System.ComponentModel;
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Logging;

namespace RazorPagesSample.TagHelpers
{
    [HtmlTargetElement("address")]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public class AddressTagHelperComponentTagHelper : TagHelperComponentTagHelper
    {
        public AddressTagHelperComponentTagHelper(
            ITagHelperComponentManager componentManager, 
            ILoggerFactory loggerFactory) : base(componentManager, loggerFactory)
        {
        }
    }
}

Sử dụng Tag Helper Component address tùy chỉnh để inject HTML markup như sau:

csharp
public class AddressTagHelperComponent : TagHelperComponent
{
    private readonly string _printableButton =
        "<button type='button' class='btn btn-info' onclick=\"window.open(" +
        "'https://binged.it/2AXRRYw')\">" +
        "<span class='glyphicon glyphicon-road' aria-hidden='true'></span>" +
        "</button>";

    public override int Order => 3;

    public override async Task ProcessAsync(TagHelperContext context,
                                            TagHelperOutput output)
    {
        if (string.Equals(context.TagName, "address",
                StringComparison.OrdinalIgnoreCase) &&
            output.Attributes.ContainsName("printable"))
        {
            var content = await output.GetChildContentAsync();
            output.Content.SetHtmlContent(
                $"<div>{content.GetContent()}</div>{_printableButton}");
        }
    }
}

Method ProcessAsync ở trên inject HTML được cung cấp cho SetHtmlContent vào phần tử <address> khớp. Việc inject xảy ra khi:

Ví dụ, câu lệnh if đánh giá là true khi xử lý phần tử <address> sau:

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