ASP.NET Core 中的編寫標籤協助程式

作者:Rick Anderson

檢視或下載範例程式碼 \(英文\) (如何下載)

開始使用標籤協助程式

本教學課程介紹如何以程式設計標籤協助程式。 標籤協助程式簡介描述標籤協助程式所提供的優點。

標籤協助程式是任何可實作 ITagHelper 介面的類別。 不過,當您編寫標籤協助程式時,通常是衍生自 TagHelper,如此可讓您存取 Process 方法。

  1. 建立稱為 AuthoringTagHelpers 的新 ASP.NET Core 專案。 您不需要驗證此專案。

  2. 建立資料夾以保存稱為 TagHelpers 的標籤協助程式。 TagHelpers 資料夾「不」是必要的,但是為合理的慣例。 現在開始撰寫一些簡單的標籤協助程式。

最精簡的標籤協助程式

在本節中,您會撰寫可更新電子郵件標籤的標籤協助程式。 例如:

<email>Support</email>

伺服器將使用我們的電子郵件標籤 (tag) 協助程式,將該標籤 (markup) 轉換成下列項目:

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

也就是,將此設為電子郵件連結的錨點標籤。 如果您要撰寫部落格引擎,並且需要它才能傳送行銷、支援和其他連絡人 (全都位在相同的網域) 的電子郵件,則可能會想要執行這項操作。

  1. 將下列 EmailTagHelper 類別新增至 TagHelpers 資料夾。

    
    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
            }
        }
    }
    
    • 標籤協助程式使用以根類別名稱的項目為目標的命名慣例 (去掉類別名稱的 TagHelper 部分)。 在此範例中,EmailTagHelper 的根名稱是 email,因此將會以 <email> 標籤為目標。 此命名慣例應該適用於大部分的標籤協助程式,稍後將示範如何行覆寫它。

    • EmailTagHelper 類別衍生自 TagHelperTagHelper 類別提供撰寫標籤協助程式的方法和屬性。

    • 覆寫的 Process 方法控制標籤協助程式在其執行時的作用。 TagHelper 類別也會使用相同的參數來提供非同步版本 (ProcessAsync)。

    • Process (和 ProcessAsync) 的內容參數包含與目前 HTML 標籤執行建立關聯的資訊。

    • Process (和 ProcessAsync) 的輸出參數包含具狀態 HTML 項目,以呈現用來產生 HTML 標籤和內容的原始來源。

    • 類別名稱的尾碼為 TagHelper,這「不」是必要的,但視為最佳做法慣例。 您可以將類別宣告為:

    public class Email : TagHelper
    
  2. 若要讓 EmailTagHelper 類別可供所有 Razor 檢視使用,請將 addTagHelper 指示詞新增至 Views/_ViewImports.cshtml 檔案:

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

    上述程式碼使用萬用字元語法,指定將使用組件中的所有標籤協助程式。 @addTagHelper 後面的第一個字串指定要載入的標籤協助程式 (使用 "*" 表示所有標籤協助程式),而第二個字串 "AuthoringTagHelpers" 指定標籤協助程式所在的組件。 另請注意,第二行使用萬用字元語法帶入 ASP.NET Core MVC 標籤協助程式 (標籤協助程式簡介會討論這些協助程式)。它是讓標籤協助程式可供 Razor 檢視使用的 @addTagHelper 指示詞。 或者,您可以提供標籤協助程式的完整名稱 (FQN),如下所示:

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

若要使用 FQN 將標籤協助程式新增至檢視,您需先新增 FQN (AuthoringTagHelpers.TagHelpers.EmailTagHelper),再新增組件名稱 (AuthoringTagHelpers,不一定要是 namespace)。 大部分開發人員都會想要使用萬用字元語法。 標籤協助程式簡介會詳述標籤協助程式新增、移除、階層和萬用字元語法。

  1. 使用下列變更更新 Views/Home/Contact.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>
    
  2. 執行應用程式,並使用慣用的瀏覽器來檢視 HTML 原始檔,讓您可以驗證電子郵件標籤已取代為錨點標籤 (例如,<a>Support</a>)。 SupportMarketing 會轉譯為連結,但沒有 href 屬性可讓它們運作。 我們將在下節修正該問題。

SetAttribute 和 SetContent

在本節中,我們將更新 EmailTagHelper,以建立電子郵件的有效錨點標籤。 我們會將它更新,以從 Razor 檢視取得資訊 (以 mail-to 屬性形式),並使用這項資訊來產生錨點。

使用下列程式碼更新 EmailTagHelper 類別:

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);
    }
}
  • 標籤協助程式依照 Pascal 命名法大小寫慣例的類別和屬性名稱會轉譯成其小寫 kebab。 因此,若要使用 MailTo 屬性,您將使用 <email mail-to="value"/> 對等項目。

  • 最後一行設定功能最小之標籤協助程式的已完成內容。

  • 反白顯示的線條會顯示新增屬性的語法:

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

只要 attributes 集合中目前沒有 "href" 屬性,該方法就適用於 "href" 屬性。 您也可以使用 output.Attributes.Add 方法,將標籤協助程式屬性新增至標籤屬性集合結尾。

  1. 使用下列變更更新 Views/Home/Contact.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>
    
  2. 執行應用程式,並驗證它會產生正確的連結。

注意

如果您要撰寫電子郵件標籤自我結尾 (<email mail-to="Rick" />),則最終輸出也會是自我結尾。 若要能夠寫入只有開始標籤的標籤 (<email mail-to="Rick">),您必須以下列項目來標記類別:

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

使用自我結尾的電子郵件標籤協助程式時,輸出會是 <a href="mailto:Rick@contoso.com" />。 自我結尾的錨點標籤不是有效的 HTML,因此您不會想要建立它;但您可能會想要建立自我結尾的標籤協助程式。 標籤協助程式會在讀取標籤之後設定 TagMode 屬性的類型。

您也可以使用 [HtmlAttributeName] 屬性,將不同的屬性名稱對應至屬性。

若要將名為 recipient 的屬性對應至 MailTo 屬性:

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

recipient 屬性的標籤協助程式:

<email recipient="…"/>

ProcessAsync

在本節中,我們將撰寫非同步電子郵件協助程式。

  1. EmailTagHelper 類別取代為下列程式碼:

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

    注意:

    • 此版本使用非同步 ProcessAsync 方法。 非同步 GetChildContentAsync 會傳回包含 TagHelperContentTask

    • 使用 output 參數,以取得 HTML 項目的內容。

  2. Views/Home/Contact.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>
    
  3. 執行應用程式,並驗證它產生有效的電子郵件連結。

RemoveAll、PreContent.SetHtmlContent 和 PostContent.SetHtmlContent

  1. 將下列 BoldTagHelper 類別新增至 TagHelpers 資料夾。

    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>");
            }
        }
    }
    
    • [HtmlTargetElement] 屬性會傳遞屬性參數,以指定是否有任何包含名為 "bold" 之 HTML 屬性的 HTML 項目相符,並且執行類別中的 Process 覆寫方法。 在我們的範例中,Process 方法會移除 "bold" 屬性,並使用 <strong></strong> 括住包含標記。

    • 因為您不想要取代現有標籤內容,所以必須使用 PreContent.SetHtmlContent 方法來撰寫開頭 <strong> 標籤,並使用 PostContent.SetHtmlContent 方法來撰寫結尾 </strong> 標籤。

  2. 修改 About.cshtml 檢視以包含 bold 屬性值。 已完成的程式碼如下所示。

    @{
        ViewData["Title"] = "About";
    }
    <h2>@ViewData["Title"].</h2>
    <h3>@ViewData["Message"]</h3>
    
    <p bold>Use this area to provide additional information.</p>
    
    <bold> Is this bold?</bold>
    
  3. 執行應用程式。 您可以使用慣用的瀏覽器來檢查原始檔,並驗證標記。

    上面的 [HtmlTargetElement] 屬性只會將目標設為提供屬性名稱 "bold" 的 HTML 標記。 標籤協助程式未曾修改 <bold> 項目。

  4. [HtmlTargetElement] 屬性行標籤為註解,而且它會預設為目標 <bold> 標籤 (tag),也就是表單 <bold> 的 HTML 標記 (markup)。 請記住,預設命名慣例將符合類別名稱 BoldTagHelper 與 <bold> 標籤。

  5. 執行應用程式,並驗證標籤協助程式已處理 <bold> 標籤。

以多個 [HtmlTargetElement] 屬性裝飾類別,會導致目標的邏輯 OR。 例如,使用下列程式碼,粗體標籤或粗體屬性會相符。

[HtmlTargetElement("bold")]
[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>");
    }
}

將多個屬性新增至相同的陳述式時,執行階段會將它們視為邏輯 AND。 例如,在下列程式碼中,HTML 項目必須命名為具有 "bold" 屬性的 "bold" (<bold bold />) 才能相符。

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

您也可以使用 [HtmlTargetElement] 來變更目標項目的名稱。 例如,如果您想要 BoldTagHelper 將目標設為 <MyBold> 標籤,您可以使用下列屬性:

[HtmlTargetElement("MyBold")]

將模型傳遞至標籤協助程式

  1. 新增 Models 資料夾。

  2. 將下列 WebsiteContext 類別新增至 Models 資料夾:

    using System;
    
    namespace AuthoringTagHelpers.Models
    {
        public class WebsiteContext
        {
            public Version Version { get; set; }
            public int CopyrightYear { get; set; }
            public bool Approved { get; set; }
            public int TagsToShow { get; set; }
        }
    }
    
  3. 將下列 WebsiteInformationTagHelper 類別新增至 TagHelpers 資料夾。

    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;
          }
       }
    }
    
    • 如前所述,標籤協助程式會將標籤協助程式依照 Pascal 大小寫 C# 命名法大小寫慣例的類別名稱和屬性轉譯成小寫 kebab。 因此,若要在 Razor 中使用 WebsiteInformationTagHelper,您將寫入 <website-information />

    • 您未明確識別具有 [HtmlTargetElement] 屬性的目標項目,因此會將預設值 website-information 設為目標。 如果您已套用下列屬性 (請注意,它不是 Kebab 大小寫,但符合類別名稱):

    [HtmlTargetElement("WebsiteInformation")]
    

    小寫 kebab 標籤 <website-information /> 將不相符。 如果您想要使用 [HtmlTargetElement] 屬性,請使用 Kebab 大小寫,如下所示:

    [HtmlTargetElement("Website-Information")]
    
    • 自我結尾項目沒有內容。 在此範例中,Razor 標記將會使用自行結束的標籤,但標籤協助程式將會建立區段元素 (這不是自行結束,而且您是在 section 元素內寫入內容)。 因此,您需要將 TagMode 設定為 StartTagAndEndTag,才能撰寫輸出。 或者,您可以將設定 TagMode 的行設定為註解,並撰寫含結尾標籤 (tag) 的標籤 (markup) (本教學課程稍後會提供範例標記)。

    • 下行中的 $ (貨幣符號) 使用插入字串

    $@"<ul><li><strong>Version:</strong> {Info.Version}</li>
    
  4. 將下列標記新增至 About.cshtml 檢視。 反白顯示的標記會顯示網站資訊。

    @using AuthoringTagHelpers.Models
    @{
        ViewData["Title"] = "About";
        WebsiteContext webContext = new WebsiteContext {
                                        Version = new Version(1, 3),
                                        CopyrightYear = 1638,
                                        Approved = true,
                                        TagsToShow = 131 };
    }
    <h2>@ViewData["Title"].</h2>
    <h3>@ViewData["Message"]</h3>
    
    <p bold>Use this area to provide additional information.</p>
    
    <bold> Is this bold?</bold>
    
    <h3> web site info </h3>
    <website-information info="webContext" />
    

    注意

    在下面所顯示的 Razor 標記中:

    <website-information info="webContext" />
    

    Razor 知道 info 屬性是類別,而不是字串,而且您想要寫入 C# 程式碼。 應該撰寫任何無 @ 字元的非字串標籤協助程式屬性。

  5. 執行應用程式,並巡覽至 About 檢視來查看網站資訊。

    注意

    您可以搭配使用下列標籤 (markup) 與結尾標籤 (tag),並移除標籤 (tag) 協助程式中包含 TagMode.StartTagAndEndTag 的行:

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

條件標籤協助程式

傳遞 true 值時,條件標籤協助程式會轉譯輸出。

  1. 將下列 ConditionTagHelper 類別新增至 TagHelpers 資料夾。

    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();
                }
            }
        }
    }
    
  2. 以下列標記取代 Views/Home/Index.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>
    
  3. Home 控制器中的 Index 方法取代為下列程式碼:

    public IActionResult Index(bool approved = false)
    {
        return View(new WebsiteContext
        {
            Approved = approved,
            CopyrightYear = 2015,
            Version = new Version(1, 3, 3, 7),
            TagsToShow = 20
        });
    }
    
  4. 執行應用程式,並瀏覽至首頁。 將不會轉譯條件式 div 中的標記。 將查詢字串 ?approved=true 附加至 URL (例如,http://localhost:1235/Home/Index?approved=true)。 approved 設定為 true,並且顯示條件式標記。

注意

使用 nameof 運算子來指定要設為目標的屬性,而不是指定字串,就像使用粗體標籤協助程式一樣:

[HtmlTargetElement(Attributes = nameof(Condition))]
 //   [HtmlTargetElement(Attributes = "condition")]
 public class ConditionTagHelper : TagHelper
{
   public bool Condition { get; set; }

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

nameof 運算子將會保護已重構的程式碼 (我們可能會想要將名稱變更為 RedCondition)。

避免標籤協助程式衝突

在本節中,您會撰寫一對自動連結標籤協助程式。 第一個會將包含開頭為 HTTP 之 URL 的標籤 (markup) 取代為包含相同 URL 的 HTML 錨點標籤 (tag) (因此產生 URL 的連結)。 第二個會針對開頭為 WWW 的 URL 執行相同的動作。

因為這兩個協助程式密切相關,而且您未來可能會將它們重構,所以我們將它們保留在相同的檔案中。

  1. 將下列 AutoLinkerHttpTagHelper 類別新增至 TagHelpers 資料夾。

    [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}
        }
    }
    

    注意

    AutoLinkerHttpTagHelper 類別將目標設為 p 項目,並使用 Regex 來建立錨點。

  2. 將下列標記新增至 Views/Home/Contact.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>
    
    <p>Visit us at http://docs.asp.net or at www.microsoft.com</p>
    
  3. 執行應用程式,並驗證標籤協助程式正確地轉譯錨點。

  4. 更新 AutoLinker 類別以包括 AutoLinkerWwwTagHelper,這會將 www 文字轉換成也包含原始 www 文字的錨點標籤。 已更新的程式碼反白顯示如下:

        [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}
            }
        }
    
        [HtmlTargetElement("p")]
        public class AutoLinkerWwwTagHelper : 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(www\.)(\S+)\b",
                     "<a target=\"_blank\" href=\"http://$0\">$0</a>"));  // www version
            }
        }
    }
    
  5. 執行應用程式。 請注意,www 文字會轉譯為連結,但 HTTP 文字則否。 如果您將中斷點放在兩個類別中,則可以看到先執行 HTTP 標籤協助程式類別。 問題在於已快取標籤協助程式輸出,而且執行 WWW 標籤協助程式時,會覆寫 HTTP 標籤協助程式的已快取輸出。 在教學課程稍後,將了解如何控制標籤協助程式的執行順序。 我們將使用下列內容來修正程式碼:

      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}
          }
      }
    
      [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
          }
      }
    

    注意

    在第一版的自動連結標籤協助程式中,您已使用下列程式碼取得目標的內容:

    var childContent = await output.GetChildContentAsync();
    

    也就是說,使用傳入 ProcessAsync 方法的 TagHelperOutput,即可呼叫 GetChildContentAsync。 如前所述,因為已快取輸出,所以會執行最後一個標籤協助程式。 您已使用下列程式碼修正該問題:

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

    上述程式碼會確認已修改內容;如果已修改,則會從輸出緩衝區中取得內容。

  6. 執行應用程式,並驗證兩個連結如預期運作。 雖然可能會顯示自動連結器標籤協助程式正確且完整,但是它有些微小問題。 如果先執行 WWW 標籤協助程式,則 www 連結會不正確。 新增 Order 多載以控制標籤執行順序,來更新程式碼。 Order 屬性可決定相對於以相同項目為目標的其他標籤協助程式的執行順序。 預設順序值為零,而且會先執行值較小的執行個體。

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

    上述程式碼保證先執行 HTTP 標籤協助程式,再執行 WWW 標籤協助程式。 將 Order 變更為 MaxValue,並驗證針對 WWW 標籤 (tag) 所產生的標籤 (markup) 不正確。

檢查並擷取子內容

標籤協助程式提供數個屬性來擷取內容。

  • GetChildContentAsync 的結果可以附加至 output.Content
  • 您可以使用 GetContent 來檢查 GetChildContentAsync 的結果。
  • 如果您修改 output.Content,則除非您呼叫 GetChildContentAsync 作為自動連結器範例,否則不會執行或轉譯 TagHelper 本文:
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}
    }
}
  • 多次呼叫 GetChildContentAsync 會傳回相同的值,而且除非您傳入 false 參數以指出不使用已快取內容,否則不會重新執行 TagHelper 本文。

載入縮小的部分檢視 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;
        }
    }