Создание вспомогательных функций тегов в ASP.NET Core

Автор: Рик Андерсон (Rick Anderson)

Просмотреть или скачать образец кода (описание загрузки)

Начало работы с вспомогательными функциями тегов

В этом учебнике приводятся основные сведения о программировании вспомогательных функций тегов. В статье Общие сведения о вспомогательных функциях тегов описываются преимущества, предоставляемые вспомогательными функциями тегов.

Вспомогательная функция тега — это любой класс, реализующий интерфейс ITagHelper. Однако при разработке вспомогательной функции тега обычно производится наследование TagHelper, так как это дает доступ к методу Process.

  1. Создайте проект ASP.NET Core с именем AuthoringTagHelpers. Проверка подлинности для этого проекта не потребуется.

  2. Создайте папку, в которой будут помещаться вспомогательные функции тегов, с именем TagHelpers. Папка TagHelpersне является обязательной; она создается согласно принятому соглашению. Теперь приступим к написанию простейших вспомогательных функций тегов.

Простейшая вспомогательная функция тега

В этом разделе вы напишете вспомогательную функцию тега, которая обновляет тег электронной почты. Например:

<email>Support</email>

Сервер будет использовать эту вспомогательную функцию тега для преобразования разметки следующим образом:

<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 является производным от TagHelper. Класс TagHelper предоставляет методы и свойства для написания вспомогательных функций тегов.

    • Переопределенный Process метод управляет действиями, выполняемыми вспомогательной функцией тега. Класс TagHelper также предоставляет асинхронную версию (ProcessAsync) с теми же параметрами.

    • Параметр контекста метода ProcessProcessAsync) содержит сведения, связанные с выполнением текущего HTML-тега.

    • Выходной параметр метода ProcessProcessAsync) содержит элемент HTML с отслеживанием состояния, который представляет источник, используемый для формирования HTML-тега и содержимого.

    • В нашем случае имя класса имеет суффикс TagHelper, который не является обязательным, но считается рекомендуемым соглашением. Класс можно объявить следующим образом:

    public class Email : TagHelper
    
  2. Чтобы сделать EmailTagHelper класс доступным для всех наших Razor представленийViews/_ViewImports.cshtml, добавьте директиву addTagHelper в файл:

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

    В приведенном выше коде используется синтаксис с подстановочным знаком, который указывает, что будут доступны все вспомогательные функции тегов в сборке. Первая строка после @addTagHelper указывает на загружаемую вспомогательную функцию тега (символ "*" соответствует всем вспомогательным функциям тегов), а вторая строка ("AuthoringTagHelpers") указывает на сборку, в которой находится вспомогательная функция тега. Кроме того, обратите внимание, что вторая строка содержит вспомогательные функции тегов ASP.NET Core MVC с помощью дикого синтаксиса карта (эти вспомогательные функции рассматриваются в разделе "Введение в вспомогательные функции тегов".) @addTagHelper Это директива, которая делает вспомогательный тег доступным для Razor представления. Вы также можете указать полное имя вспомогательной функции тега, как показано ниже.

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

Чтобы добавить вспомогательную функцию тега в представление с помощью полного имени, сначала добавьте полное имя (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>). Строки Support и Marketing отображаются как ссылки, но у них нет атрибута 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, для вспомогательных функций тегов преобразуются в кебаб-стиль. Поэтому для использования атрибута 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);
}

Такой подход работает для атрибута 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 возвращает объект Task, содержащий TagHelperContent.

    • Для получения содержимого элемента HTML используйте параметр output.

  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] передает параметр атрибута, который указывает, что любой элемент HTML, содержащий атрибут HTML с именем bold, будет соответствовать условиям и метод переопределения Process в классе будет выполняться. В этом примере метод Process удаляет атрибут bold и заключает содержащую разметку в теги <strong></strong>.

    • Так как заменять существующее содержимое тега не нужно, открывающий тег <strong> должен записываться с помощью метода PreContent.SetHtmlContent, а закрывающий тег </strong> — с помощью метода PostContent.SetHtmlContent.

  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] предназначен только для разметки HTML, которая предоставляет имя атрибута bold. Элемент <bold> не был изменен вспомогательной функцией тега.

  4. Если закомментировать строку с атрибутом [HtmlTargetElement], функция будет нацелена по умолчанию на теги <bold>, то есть на разметку HTML в форме <bold>. Помните, что в соответствии с соглашением об именовании по умолчанию имя класса BoldTagHelper соответствует тегам <bold>.

  5. Запустите приложение и убедитесь в том, что тег <bold> обрабатывается вспомогательной функцией тега.

Если декорировать класс несколькими атрибутами [HtmlTargetElement], к целевым тегам применяется логическая операция ИЛИ. Например, в приведенном ниже коде условиям будет соответствовать тег bold или атрибут bold.

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

Если в один оператор добавляются несколько атрибутов, среда выполнения применяет к ним логическую операцию И. Например, в приведенном ниже коде элемент 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;
          }
       }
    }
    
    • Как было сказано ранее, имена классов и свойств C# в стиле Pascal для вспомогательных функций тегов преобразуются в кебаб-стиль. Таким образом, чтобы использовать вход WebsiteInformationTagHelperRazor, вы напишете <website-information />.

    • Целевой элемент не определяется напрямую с помощью атрибута [HtmlTargetElement], поэтому по умолчанию целевым будет элемент website-information. Например, вы применяете следующий атрибут (обратите внимание, что он не в стиле кебаб, но соответствует имени класса):

    [HtmlTargetElement("WebsiteInformation")]
    

    Ему не будет соответствовать тег в стиле кебаб <website-information />. Чтобы использовать атрибут [HtmlTargetElement], следует применить стиль кебаб, как показано ниже.

    [HtmlTargetElement("Website-Information")]
    
    • Самозакрывающиеся элементы не имеют содержимого. В этом примере разметка Razor будет использовать самозаверяющий тег, но вспомогательный элемент тега будет создавать элемент section (который не самозаверяется и вы пишете содержимое внутри section элемента). Поэтому для записи выходных данных следует присвоить свойству TagMode значение StartTagAndEndTag. Кроме того, можно закомментировать строку, в которой задается TagMode, и написать разметку с закрывающим тегом. (Пример разметки приводится далее в этом руководстве.)

    • Символ $ (знак доллара) в приведенной ниже строке определяет использование интерполированной строки.

    $@"<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" />
    

    Razorinfo знает, что атрибут является классом, а не строкой, и вы хотите написать код C#. Любой нестроковый атрибут вспомогательной функции тега должен быть записан без символа @.

  5. Запустите приложение и перейдите к представлению About, чтобы просмотреть сведения о веб-сайте.

    Примечание.

    Вы можете использовать следующую разметку с закрывающим тегом и удалить строку со свойством 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. Замените метод Index в контроллере Home следующим кодом:

    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, а не указывайте строку, как в случае со вспомогательной функцией тега bold:

[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).

Как избежать конфликтов между вспомогательными функциями тегов

В этом разделе вы напишете пару вспомогательных функций тегов для автоматического связывания. Первая функция будет заменять разметку, которая содержит URL-адрес, начинающийся с префикса HTTP, на HTML-тег привязки, содержащий тот же URL-адрес (то есть предоставляющий ссылку на URL-адрес). Вторая функция будет делать то же самое для URL-адреса, начинающегося с WWW.

Так как эти две вспомогательные функции тесно связаны друг с другом и в будущем может потребоваться их рефакторинг, мы поместим их в один файл.

  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, и в нем используется регулярное выражение для создания привязки.

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

    То есть вызывался метод GetChildContentAsync с передачей объекта TagHelperOutput в метод ProcessAsync. Как было сказано ранее, из-за кэширования выходных данных приоритет имеет последняя выполняемая вспомогательная функция тега. Эта проблема исправлялась с помощью следующего кода:

    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 разметка создается неправильно.

Проверка и извлечение содержимого дочернего элемента

Вспомогательные функции тегов предоставляют несколько свойств для извлечения содержимого.

  • Результат выполнения метода GetChildContentAsync можно добавить к output.Content.
  • Результат выполнения метода GetChildContentAsync можно проверить с помощью GetContent.
  • При изменении output.Content тело функции TagHelper будет выполняться или обрабатываться, только если вызвать метод GetChildContentAsync, как в нашем примере автоматического связывания.
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 возвращается одно и то же значение и тело функции TagHelper не выполняется повторно, если только не передать параметр false, который указывает на то, что не следует использовать кэшированный результат.

Загрузка функции 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;
        }
    }