ASP.NET Core 中的編寫標籤協助程式Author Tag Helpers in ASP.NET Core

作者:Rick AndersonBy Rick Anderson

查看或下載範例程式碼如何下載View or download sample code (how to download)

開始使用標籤協助程式Get started with Tag Helpers

本教學課程介紹如何以程式設計標籤協助程式。This tutorial provides an introduction to programming Tag Helpers. 標籤協助程式簡介描述標籤協助程式所提供的優點。Introduction to Tag Helpers describes the benefits that Tag Helpers provide.

標籤協助程式是任何可實作 ITagHelper 介面的類別。A tag helper is any class that implements the ITagHelper interface. 不過,當您編寫標籤協助程式時,通常是衍生自 TagHelper,如此可讓您存取 Process 方法。However, when you author a tag helper, you generally derive from TagHelper, doing so gives you access to the Process method.

  1. 建立稱為 AuthoringTagHelpers 的新 ASP.NET Core 專案。Create a new ASP.NET Core project called AuthoringTagHelpers. 您不需要驗證此專案。You won't need authentication for this project.

  2. 建立資料夾以保存稱為 TagHelpers 的標籤協助程式。Create a folder to hold the Tag Helpers called TagHelpers. TagHelpers 資料夾「不」** 是必要的,但是為合理的慣例。The TagHelpers folder is not required, but it's a reasonable convention. 現在開始撰寫一些簡單的標籤協助程式。Now let's get started writing some simple tag helpers.

最精簡的標籤協助程式A minimal Tag Helper

在本節中,您會撰寫可更新電子郵件標籤的標籤協助程式。In this section, you write a tag helper that updates an email tag. 例如:For example:

<email>Support</email>

伺服器將使用我們的電子郵件標籤 (tag) 協助程式,將該標籤 (markup) 轉換成下列項目:The server will use our email tag helper to convert that markup into the following:

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

也就是,將此設為電子郵件連結的錨點標籤。That is, an anchor tag that makes this an email link. 如果您要撰寫部落格引擎,並且需要它才能傳送行銷、支援和其他連絡人 (全都位在相同的網域) 的電子郵件,則可能會想要執行這項操作。You might want to do this if you are writing a blog engine and need it to send email for marketing, support, and other contacts, all to the same domain.

  1. 將下列 EmailTagHelper 類別新增至 TagHelpers 資料夾。Add the following EmailTagHelper class to the TagHelpers folder.

    
    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 部分)。Tag helpers use a naming convention that targets elements of the root class name (minus the TagHelper portion of the class name). 在此範例中,EmailTagHelper 的根名稱是 email,因此將會以 <email> 標籤為目標。In this example, the root name of EmailTagHelper is email, so the <email> tag will be targeted. 此命名慣例應該適用於大部分的標籤協助程式,稍後將示範如何行覆寫它。This naming convention should work for most tag helpers, later on I'll show how to override it.

    • EmailTagHelper 類別衍生自 TagHelperThe EmailTagHelper class derives from TagHelper. TagHelper 類別提供撰寫標籤協助程式的方法和屬性。The TagHelper class provides methods and properties for writing Tag Helpers.

    • 覆寫的 Process 方法控制標籤協助程式在其執行時的作用。The overridden Process method controls what the tag helper does when executed. TagHelper 類別也會使用相同的參數來提供非同步版本 (ProcessAsync)。The TagHelper class also provides an asynchronous version (ProcessAsync) with the same parameters.

    • Process (和 ProcessAsync) 的內容參數包含與目前 HTML 標籤執行建立關聯的資訊。The context parameter to Process (and ProcessAsync) contains information associated with the execution of the current HTML tag.

    • Process (和 ProcessAsync) 的輸出參數包含具狀態 HTML 項目,以呈現用來產生 HTML 標籤和內容的原始來源。The output parameter to Process (and ProcessAsync) contains a stateful HTML element representative of the original source used to generate an HTML tag and content.

    • 類別名稱的尾碼為 TagHelper,這「不」** 是必要的,但視為最佳做法慣例。Our class name has a suffix of TagHelper, which is not required, but it's considered a best practice convention. 您可以將類別宣告為:You could declare the class as:

    public class Email : TagHelper
    
  2. 若要讓EmailTagHelper類別可供所有的Razor視圖使用,請addTagHelper將指示詞新增至views/_ViewImports. cshtml檔案:To make the EmailTagHelper class available to all our Razor views, add the addTagHelper directive to the Views/_ViewImports.cshtml file:

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

    上述程式碼使用萬用字元語法,指定將使用組件中的所有標籤協助程式。The code above uses the wildcard syntax to specify all the tag helpers in our assembly will be available. @addTagHelper 後面的第一個字串指定要載入的標籤協助程式 (使用 "*" 表示所有標籤協助程式),而第二個字串 "AuthoringTagHelpers" 指定標籤協助程式所在的組件。The first string after @addTagHelper specifies the tag helper to load (Use "*" for all tag helpers), and the second string "AuthoringTagHelpers" specifies the assembly the tag helper is in. 另請注意,第二行會使用萬用字元語法來帶入 ASP.NET Core MVC 標籤協助程式(標記協助程式簡介中會討論這些 helper)。這是@addTagHelper讓標籤協助程式可供Razor視圖使用的指示詞。Also, note that the second line brings in the ASP.NET Core MVC tag helpers using the wildcard syntax (those helpers are discussed in Introduction to Tag Helpers.) It's the @addTagHelper directive that makes the tag helper available to the Razor view. 或者,您可以提供標籤協助程式的完整名稱 (FQN),如下所示:Alternatively, you can provide the fully qualified name (FQN) of a tag helper as shown below:

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

若要使用 FQN 將標籤協助程式新增至檢視,您需先新增 FQN (AuthoringTagHelpers.TagHelpers.EmailTagHelper),再新增組件名稱 (AuthoringTagHelpers,不一定要是 namespace)。To add a tag helper to a view using a FQN, you first add the FQN (AuthoringTagHelpers.TagHelpers.EmailTagHelper), and then the assembly name (AuthoringTagHelpers, not necessarily the namespace). 大部分開發人員都會想要使用萬用字元語法。Most developers will prefer to use the wildcard syntax. 標籤協助程式簡介會詳述標籤協助程式新增、移除、階層和萬用字元語法。Introduction to Tag Helpers goes into detail on tag helper adding, removing, hierarchy, and wildcard syntax.

  1. 使用下列變更來更新 Views/Home/Contact.cshtml 檔案中的標記:Update the markup in the Views/Home/Contact.cshtml file with these changes:

    @{
        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>)。Run the app and use your favorite browser to view the HTML source so you can verify that the email tags are replaced with anchor markup (For example, <a>Support</a>). SupportMarketing 會轉譯為連結,但沒有 href 屬性可讓它們運作。Support and Marketing are rendered as a links, but they don't have an href attribute to make them functional. 我們將在下節修正該問題。We'll fix that in the next section.

SetAttribute 和 SetContentSetAttribute and SetContent

在本節中,我們將更新 EmailTagHelper,以建立電子郵件的有效錨點標籤。In this section, we'll update the EmailTagHelper so that it will create a valid anchor tag for email. 我們會將它更新為從Razor視圖中取出資訊(以mail-to屬性的形式),並使用它來產生錨點。We'll update it to take information from a Razor view (in the form of a mail-to attribute) and use that in generating the anchor.

使用下列程式碼更新 EmailTagHelper 類別:Update the EmailTagHelper class with the following:

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 命名法大小寫慣例的類別和屬性名稱會轉譯成其小寫 kebabPascal-cased class and property names for tag helpers are translated into their kebab case. 因此,若要使用 MailTo 屬性,您將使用 <email mail-to="value"/> 對等項目。Therefore, to use the MailTo attribute, you'll use <email mail-to="value"/> equivalent.

  • 最後一行設定功能最小之標籤協助程式的已完成內容。The last line sets the completed content for our minimally functional tag helper.

  • 反白顯示的線條會顯示新增屬性的語法:The highlighted line shows the syntax for adding attributes:

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" 屬性。That approach works for the attribute "href" as long as it doesn't currently exist in the attributes collection. 您也可以使用 output.Attributes.Add 方法,將標籤協助程式屬性新增至標籤屬性集合結尾。You can also use the output.Attributes.Add method to add a tag helper attribute to the end of the collection of tag attributes.

  1. 使用下列變更來更新 Views/Home/Contact.cshtml 檔案中的標記:Update the markup in the Views/Home/Contact.cshtml file with these changes:

    @{
        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. 執行應用程式,並驗證它會產生正確的連結。Run the app and verify that it generates the correct links.

注意

如果您要撰寫電子郵件標籤自我結尾 (<email mail-to="Rick" />),則最終輸出也會是自我結尾。If you were to write the email tag self-closing (<email mail-to="Rick" />), the final output would also be self-closing. 若要啟用只使用開始標記(<email mail-to="Rick">)寫入標記的功能,您必須使用下列內容來標記類別:To enable the ability to write the tag with only a start tag (<email mail-to="Rick">) you must mark the class with the following:

[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" />With a self-closing email tag helper, the output would be <a href="mailto:Rick@contoso.com" />. 自我結尾的錨點標籤不是有效的 HTML,因此您不會想要建立它;但您可能會想要建立自我結尾的標籤協助程式。Self-closing anchor tags are not valid HTML, so you wouldn't want to create one, but you might want to create a tag helper that's self-closing. 標籤協助程式會在讀取標籤之後設定 TagMode 屬性的類型。Tag helpers set the type of the TagMode property after reading a tag.

ProcessAsyncProcessAsync

在本節中,我們將撰寫非同步電子郵件協助程式。In this section, we'll write an asynchronous email helper.

  1. EmailTagHelper 類別取代為下列程式碼:Replace the EmailTagHelper class with the following code:

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

    注意:Notes:

    • 此版本使用非同步 ProcessAsync 方法。This version uses the asynchronous ProcessAsync method. 非同步 GetChildContentAsync 會傳回包含 TagHelperContentTaskThe asynchronous GetChildContentAsync returns a Task containing the TagHelperContent.

    • 使用 output 參數,以取得 HTML 項目的內容。Use the output parameter to get contents of the HTML element.

  2. Views/Home/Contact.cshtml 檔案進行下列變更,讓標籤協助程式可以取得目標電子郵件。Make the following change to the Views/Home/Contact.cshtml file so the tag helper can get the target email.

    @{
        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. 執行應用程式,並驗證它產生有效的電子郵件連結。Run the app and verify that it generates valid email links.

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

  1. 將下列 BoldTagHelper 類別新增至 TagHelpers 資料夾。Add the following BoldTagHelper class to the TagHelpers folder.

    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 覆寫方法。The [HtmlTargetElement] attribute passes an attribute parameter that specifies that any HTML element that contains an HTML attribute named "bold" will match, and the Process override method in the class will run. 在我們的範例中,Process 方法會移除 "bold" 屬性,並使用 <strong></strong> 括住包含標記。In our sample, the Process method removes the "bold" attribute and surrounds the containing markup with <strong></strong>.

    • 因為您不想要取代現有標籤內容,所以必須使用 PreContent.SetHtmlContent 方法來撰寫開頭 <strong> 標籤,並使用 PostContent.SetHtmlContent 方法來撰寫結尾 </strong> 標籤。Because you don't want to replace the existing tag content, you must write the opening <strong> tag with the PreContent.SetHtmlContent method and the closing </strong> tag with the PostContent.SetHtmlContent method.

  2. 修改 About.cshtml 檢視,以包含 bold 屬性值。Modify the About.cshtml view to contain a bold attribute value. 已完成的程式碼如下所示。The completed code is shown below.

    @{
        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. 執行應用程式。Run the app. 您可以使用慣用的瀏覽器來檢查原始檔,並驗證標記。You can use your favorite browser to inspect the source and verify the markup.

    上面的 [HtmlTargetElement] 屬性只會將目標設為提供屬性名稱 "bold" 的 HTML 標記。The [HtmlTargetElement] attribute above only targets HTML markup that provides an attribute name of "bold". 標籤協助程式未曾修改 <bold> 項目。The <bold> element wasn't modified by the tag helper.

  4. [HtmlTargetElement] 屬性行標籤為註解,而且它會預設為目標 <bold> 標籤 (tag),也就是表單 <bold> 的 HTML 標記 (markup)。Comment out the [HtmlTargetElement] attribute line and it will default to targeting <bold> tags, that is, HTML markup of the form <bold>. 請記住,預設命名慣例將符合類別名稱 BoldTagHelper 與 <bold> 標籤。Remember, the default naming convention will match the class name BoldTagHelper to <bold> tags.

  5. 執行應用程式,並驗證標籤協助程式已處理 <bold> 標籤。Run the app and verify that the <bold> tag is processed by the tag helper.

以多個 [HtmlTargetElement] 屬性裝飾類別,會導致目標的邏輯 OR。Decorating a class with multiple [HtmlTargetElement] attributes results in a logical-OR of the targets. 例如,使用下列程式碼,粗體標籤或粗體屬性會相符。For example, using the code below, a bold tag or a bold attribute will match.

[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。When multiple attributes are added to the same statement, the runtime treats them as a logical-AND. 例如,在下列程式碼中,HTML 項目必須命名為具有 "bold" 屬性的 "bold" (<bold bold />) 才能相符。For example, in the code below, an HTML element must be named "bold" with an attribute named "bold" (<bold bold />) to match.

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

您也可以使用 [HtmlTargetElement] 來變更目標項目的名稱。You can also use the [HtmlTargetElement] to change the name of the targeted element. 例如,如果您想要 BoldTagHelper 將目標設為 <MyBold> 標籤,您可以使用下列屬性:For example if you wanted the BoldTagHelper to target <MyBold> tags, you would use the following attribute:

[HtmlTargetElement("MyBold")]

將模型傳遞至標籤協助程式Pass a model to a Tag Helper

  1. 新增 Models 資料夾。Add a Models folder.

  2. 將下列 WebsiteContext 類別新增至 Models 資料夾:Add the following WebsiteContext class to the Models folder:

    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 資料夾。Add the following WebsiteInformationTagHelper class to the TagHelpers folder.

    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# 命名法大小寫慣例的類別名稱和屬性轉譯成小寫 kebabAs mentioned previously, tag helpers translates Pascal-cased C# class names and properties for tag helpers into kebab case. 因此,若要使用WebsiteInformationTagHelper中Razor的,您將<website-information />會撰寫。Therefore, to use the WebsiteInformationTagHelper in Razor, you'll write <website-information />.

    • 您未明確識別具有 [HtmlTargetElement] 屬性的目標項目,因此會將預設值 website-information 設為目標。You are not explicitly identifying the target element with the [HtmlTargetElement] attribute, so the default of website-information will be targeted. 如果您已套用下列屬性 (請注意,它不是 Kebab 大小寫,但符合類別名稱):If you applied the following attribute (note it's not kebab case but matches the class name):

    [HtmlTargetElement("WebsiteInformation")]
    

    小寫 kebab 標籤 <website-information /> 將不相符。The kebab case tag <website-information /> wouldn't match. 如果您想要使用 [HtmlTargetElement] 屬性,請使用 Kebab 大小寫,如下所示:If you want use the [HtmlTargetElement] attribute, you would use kebab case as shown below:

    [HtmlTargetElement("Website-Information")]
    
    • 自我結尾項目沒有內容。Elements that are self-closing have no content. 在Razor此範例中,標記會使用自我結束記號,但標籤協助程式將會建立區段元素(這不是自行關閉,而且您會在專案內section寫入內容)。For this example, the Razor markup will use a self-closing tag, but the tag helper will be creating a section element (which isn't self-closing and you are writing content inside the section element). 因此,您需要將 TagMode 設定為 StartTagAndEndTag,才能撰寫輸出。Therefore, you need to set TagMode to StartTagAndEndTag to write output. 或者,您可以將設定 TagMode 的行設定為註解,並撰寫含結尾標籤 (tag) 的標籤 (markup) Alternatively, you can comment out the line setting TagMode and write markup with a closing tag. (本教學課程稍後會提供範例標記)。(Example markup is provided later in this tutorial.)

    • 下行中的 $ (貨幣符號) 使用插入字串The $ (dollar sign) in the following line uses an interpolated string:

    $@"<ul><li><strong>Version:</strong> {Info.Version}</li>
    
  4. 將下列標記新增至 About.cshtml 檢視。Add the following markup to the About.cshtml view. 反白顯示的標記會顯示網站資訊。The highlighted markup displays the web site information.

    @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所示的標記中:In the Razor markup shown below:

    <website-information info="webContext" />
    

    Razor知道info屬性是一個類別,而不是字串,而您想要撰寫 c # 程式碼。 knows the info attribute is a class, not a string, and you want to write C# code. 應該撰寫任何無 @ 字元的非字串標籤協助程式屬性。Any non-string tag helper attribute should be written without the @ character.

  5. 執行應用程式,並巡覽至 About 檢視來查看網站資訊。Run the app, and navigate to the About view to see the web site information.

    注意

    您可以搭配使用下列標籤 (markup) 與結尾標籤 (tag),並移除標籤 (tag) 協助程式中包含 TagMode.StartTagAndEndTag 的行:You can use the following markup with a closing tag and remove the line with TagMode.StartTagAndEndTag in the tag helper:

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

條件標籤協助程式Condition Tag Helper

傳遞 true 值時,條件標籤協助程式會轉譯輸出。The condition tag helper renders output when passed a true value.

  1. 將下列 ConditionTagHelper 類別新增至 TagHelpers 資料夾。Add the following ConditionTagHelper class to the TagHelpers folder.

    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 檔案的內容取代為下列標記:Replace the contents of the Views/Home/Index.cshtml file with the following markup:

    @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 方法取代為下列程式碼:Replace the Index method in the Home controller with the following code:

    public IActionResult Index(bool approved = false)
    {
        return View(new WebsiteContext
        {
            Approved = approved,
            CopyrightYear = 2015,
            Version = new Version(1, 3, 3, 7),
            TagsToShow = 20
        });
    }
    
  4. 執行應用程式,並瀏覽至首頁。Run the app and browse to the home page. 將不會轉譯條件式 div 中的標記。The markup in the conditional div won't be rendered. 將查詢字串 ?approved=true 附加至 URL (例如,http://localhost:1235/Home/Index?approved=true)。Append the query string ?approved=true to the URL (for example, http://localhost:1235/Home/Index?approved=true). approved 設定為 true,並且顯示條件式標記。approved is set to true and the conditional markup will be displayed.

注意

使用 nameof 運算子來指定要設為目標的屬性,而不是指定字串,就像使用粗體標籤協助程式一樣:Use the nameof operator to specify the attribute to target rather than specifying a string as you did with the bold tag helper:

[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)。The nameof operator will protect the code should it ever be refactored (we might want to change the name to RedCondition).

避免標籤協助程式衝突Avoid Tag Helper conflicts

在本節中,您會撰寫一對自動連結標籤協助程式。In this section, you write a pair of auto-linking tag helpers. 第一個會將包含開頭為 HTTP 之 URL 的標籤 (markup) 取代為包含相同 URL 的 HTML 錨點標籤 (tag) (因此產生 URL 的連結)。The first will replace markup containing a URL starting with HTTP to an HTML anchor tag containing the same URL (and thus yielding a link to the URL). 第二個會針對開頭為 WWW 的 URL 執行相同的動作。The second will do the same for a URL starting with WWW.

因為這兩個協助程式密切相關,而且您未來可能會將它們重構,所以我們將它們保留在相同的檔案中。Because these two helpers are closely related and you may refactor them in the future, we'll keep them in the same file.

  1. 將下列 AutoLinkerHttpTagHelper 類別新增至 TagHelpers 資料夾。Add the following AutoLinkerHttpTagHelper class to the TagHelpers folder.

    [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 來建立錨點。The AutoLinkerHttpTagHelper class targets p elements and uses Regex to create the anchor.

  2. 將下列標記新增至 Views/Home/Contact.cshtml 檔案結尾:Add the following markup to the end of the Views/Home/Contact.cshtml file:

    @{
        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. 執行應用程式,並驗證標籤協助程式正確地轉譯錨點。Run the app and verify that the tag helper renders the anchor correctly.

  4. 更新 AutoLinker 類別以包括 AutoLinkerWwwTagHelper,這會將 www 文字轉換成也包含原始 www 文字的錨點標籤。Update the AutoLinker class to include the AutoLinkerWwwTagHelper which will convert www text to an anchor tag that also contains the original www text. 已更新的程式碼反白顯示如下:The updated code is highlighted below:

        [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. 執行應用程式。Run the app. 請注意,www 文字會轉譯為連結,但 HTTP 文字則否。Notice the www text is rendered as a link but the HTTP text isn't. 如果您將中斷點放在兩個類別中,則可以看到先執行 HTTP 標籤協助程式類別。If you put a break point in both classes, you can see that the HTTP tag helper class runs first. 問題在於已快取標籤協助程式輸出,而且執行 WWW 標籤協助程式時,會覆寫 HTTP 標籤協助程式的已快取輸出。The problem is that the tag helper output is cached, and when the WWW tag helper is run, it overwrites the cached output from the HTTP tag helper. 在教學課程稍後,將了解如何控制標籤協助程式的執行順序。Later in the tutorial we'll see how to control the order that tag helpers run in. 我們將使用下列內容來修正程式碼:We'll fix the code with the following:

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

    注意

    在第一版的自動連結標籤協助程式中,您已使用下列程式碼取得目標的內容:In the first edition of the auto-linking tag helpers, you got the content of the target with the following code:

    var childContent = await output.GetChildContentAsync();
    

    也就是說,使用傳入 ProcessAsync 方法的 TagHelperOutput,即可呼叫 GetChildContentAsyncThat is, you call GetChildContentAsync using the TagHelperOutput passed into the ProcessAsync method. 如前所述,因為已快取輸出,所以會執行最後一個標籤協助程式。As mentioned previously, because the output is cached, the last tag helper to run wins. 您已使用下列程式碼修正該問題:You fixed that problem with the following code:

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

    上述程式碼會確認已修改內容;如果已修改,則會從輸出緩衝區中取得內容。The code above checks to see if the content has been modified, and if it has, it gets the content from the output buffer.

  6. 執行應用程式,並驗證兩個連結如預期運作。Run the app and verify that the two links work as expected. 雖然可能會顯示自動連結器標籤協助程式正確且完整,但是它有些微小問題。While it might appear our auto linker tag helper is correct and complete, it has a subtle problem. 如果先執行 WWW 標籤協助程式,則 www 連結會不正確。If the WWW tag helper runs first, the www links won't be correct. 新增 Order 多載以控制標籤執行順序,來更新程式碼。Update the code by adding the Order overload to control the order that the tag runs in. Order 屬性可決定相對於以相同項目為目標的其他標籤協助程式的執行順序。The Order property determines the execution order relative to other tag helpers targeting the same element. 預設順序值為零,而且會先執行值較小的執行個體。The default order value is zero and instances with lower values are executed first.

    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 標籤協助程式。The preceding code guarantees that the HTTP tag helper runs before the WWW tag helper. Order 變更為 MaxValue,並驗證針對 WWW 標籤 (tag) 所產生的標籤 (markup) 不正確。Change Order to MaxValue and verify that the markup generated for the WWW tag is incorrect.

檢查並擷取子內容Inspect and retrieve child content

標籤協助程式提供數個屬性來擷取內容。The tag helpers provide several properties to retrieve content.

  • GetChildContentAsync 的結果可以附加至 output.ContentThe result of GetChildContentAsync can be appended to output.Content.
  • 您可以使用 GetContent 來檢查 GetChildContentAsync 的結果。You can inspect the result of GetChildContentAsync with GetContent.
  • 如果您修改 output.Content,則除非您呼叫 GetChildContentAsync 作為自動連結器範例,否則不會執行或轉譯 TagHelper 本文:If you modify output.Content, the TagHelper body won't be executed or rendered unless you call GetChildContentAsync as in our auto-linker sample:
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 本文。Multiple calls to GetChildContentAsync returns the same value and doesn't re-execute the TagHelper body unless you pass in a false parameter indicating not to use the cached result.

載入縮小的部分檢視 TagHelperLoad minified partial view TagHelper

在生產環境中,效能可以透過載入縮小的部分檢視來改善。In production environments, performance can be improved by loading minified partial views. 在生產環境中利用縮小的部分檢視:To take advantage of minified partial view in production:

  • 建立/設定可縮小部分檢視的建置前程序。Create/set up a pre-build process that minifies partial views.
  • 使用下列程式碼,在非開發環境中載入縮小的部分檢視。Use the following code to load minified partial views in non-development environments.
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;
        }
    }