ASP.NET Core의 작성자 태그 도우미

작성자: Rick Anderson

샘플 코드 보기 및 다운로드(다운로드 방법)

태그 도우미 시작

이 자습서는 태그 도우미 프로그래밍에 대한 소개를 제공합니다. 태그 도우미 소개에서는 태그 도우미가 제공하는 이점에 대해 설명합니다.

태그 도우미는 ITagHelper 인터페이스를 구현하는 클래스입니다. 그러나 태그 도우미를 작성할 때 일반적으로 TagHelper에서 파생되므로 Process 메서드에 액세스할 수 있습니다.

  1. AuthoringTagHelpers라는 새로운 ASP.NET Core 프로젝트를 만듭니다. 이 프로젝트에 대한 인증이 필요하지 않습니다.

  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)을 제공합니다.

    • Process(및 ProcessAsync)에 대한 컨텍스트 매개 변수는 현재 HTML 태그의 실행과 관련된 정보를 포함합니다.

    • Process(및 ProcessAsync)에 대한 출력 매개 변수는 HTML 태그 및 콘텐츠를 생성하는 데 사용된 원본 소스의 상태 저장 HTML 요소 표현을 포함합니다.

    • 클래스 이름에는 TagHelper라는 접미사가 있으며 필수는 아니지만 관례적으로 사용됩니다. 다음과 같이 클래스를 선언할 수 있습니다.

    public class Email : TagHelper
    
  2. 모든 Razor 보기에서 EmailTagHelper 클래스를 사용할 수 있도록 하려면 지시문을 Views/_ViewImports.cshtml 파일에 추가 addTagHelper 합니다.

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

    위의 코드에서는 와일드 카드 구문을 사용하여 사용할 수 있는 모든 태그 도우미를 어셈블리에서 지정합니다. @addTagHelper 뒤의 첫 번째 문자열은 로드할 태그 도우미(모든 태그 도우미에 "*" 사용)를 지정하고 두 번째 문자열 "AuthoringTagHelpers"는 태그 도우미가 있는 어셈블리를 지정합니다. 또한 두 번째 줄은 와일드 카드 구문을 사용하여 ASP.NET Core MVC 태그 도우미를 제공합니다(해당 도우미에 대해서는 태그 도우미 소개에서 설명). @addTagHelper 지시문은 태그 도우미를 Razor 뷰에서 사용할 수 있도록 하는 지시문입니다. 또는 아래 표시된 것처럼 태그 도우미의 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>). 지원마케팅은 링크로 렌더링되지만 작동하도록 하는 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);
    }
}
  • 태그 도우미에 대한 파스칼식 클래스 및 속성 이름이 kebab case로 변환됩니다. 따라서 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 메서드를 사용합니다. 비동기 GetChildContentAsyncTagHelperContent가 포함된 Task를 반환합니다.

    • 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> 태그를 대상으로 합니다. 즉, <bold> 형식의 HTML 태그입니다. 기본 명명 규칙은 클래스 이름 BoldTagHelper를 <bold> 태그와 일치시킨다는 점을 유의합니다.

  5. 앱을 실행하고 <bold> 태그가 태그 도우미에 의해 처리되는지 확인합니다.

클래스를 여러 개의 [HtmlTargetElement] 특성으로 데코레이팅하면 그 결과는 대상의 논리 OR입니다. 예를 들어 아래 코드를 사용하여 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>");
    }
}

동일한 문에 특성이 여러 개 추가된 경우, 런타임에서 논리 AND로 처리합니다. 예를 들어 아래 코드에서는 일치시킬 "bold"(<bold bold />) 특성을 사용하여 HTML 요소 이름을 "bold"로 지정해야 합니다.

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

또는 [HtmlTargetElement]를 사용하여 대상 요소의 이름을 변경할 수 있습니다. 예를 들어 BoldTagHelper<MyBold> 태그를 대상으로 지정하도록 하려면 다음 특성을 사용합니다.

[HtmlTargetElement("MyBold")]

모델을 태그 도우미에 전달

  1. 모델 폴더를 추가합니다.

  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# 클래스 이름과 태그 도우미 속성을 kebab case로 변환합니다. 따라서 Razor에서 WebsiteInformationTagHelper를 사용하려면 <website-information />을 작성합니다.

    • [HtmlTargetElement] 특성을 사용하여 대상 요소를 명시적으로 식별하지 않으므로 website-information의 기본값이 대상으로 지정됩니다. 다음 특성을 적용한 경우(kebab 대/소문자는 아니지만 클래스 이름 일치):

    [HtmlTargetElement("WebsiteInformation")]
    

    kebab case 태그 <website-information />은 일치하지 않습니다. [HtmlTargetElement] 특성을 사용하려는 경우 아래와 같이 kebab 대/소문자를 사용합니다.

    [HtmlTargetElement("Website-Information")]
    
    • 자체 닫음 요소에는 내용이 없습니다. 이 예제에서 Razor 태그는 자체 닫음 태그를 사용하지만, 태그 도우미는 section 요소(자체 닫음이 아니며 section 요소 내부에 내용 작성 중)를 만들 것입니다. 따라서 TagModeStartTagAndEndTag로 설정하여 출력을 작성해야 합니다. 또는 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" />
    

    Razor는 info 특성이 문자열이 아니라 클래스임을 알고 있으며 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. 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 연산자를 사용하여 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으로 변경할 수 있음).

태그 도우미 충돌 방지

이 섹션에서는 자동 링크 태그 도우미 쌍을 작성합니다. 첫 번째는 HTTP로 시작하는 URL을 포함하는 태그를 동일한 URL을 포함하는 HTML 앵커 태그로 대체합니다(따라서 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. www 텍스트를 원본 www 텍스트를 포함하는 앵커 태그로 변환할 AutoLinkerWwwTagHelper를 포함하도록 AutoLinker 클래스를 업데이트합니다. 업데이트된 코드는 아래에 강조 표시됩니다.

        [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 속성은 동일한 요소를 대상으로 하는 다른 태그 도우미를 기준으로 실행 순서를 결정합니다. 기본 순서 값은 0이고 값이 낮은 인스턴스가 먼저 실행됩니다.

    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 태그 도우미보다 먼저 실행되도록 보장합니다. OrderMaxValue로 변경하고 WWW 태그에 대해 보장된 태그가 잘못되었는지 확인합니다.

자식 콘텐츠 검사 및 검색

태그 도우미는 콘텐츠를 검색하기 위한 여러 가지 속성을 제공합니다.

  • GetChildContentAsync의 결과는 output.Content에 추가할 수 있습니다.
  • GetContentGetChildContentAsync의 결과를 검사할 수 있습니다.
  • 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;
        }
    }