次の方法で共有


ASP.NET Core のタグ ヘルパー コンポーネント

Scott AddieFiyaz Bin Hasan

タグ ヘルパー コンポーネントは、サーバー側コードから HTML 要素を条件付きで変更または追加できるタグ ヘルパーです。 この機能は、ASP.NET Core 2.0 以降で使用できます。

ASP.NET Core には、 headbodyの 2 つの組み込みのタグ ヘルパー コンポーネントが含まれています。 これらは Microsoft.AspNetCore.Mvc.Razor.TagHelpers 名前空間にあり、MVC と Razor Pages の両方で使用できます。 タグ ヘルパー コンポーネントでは、 _ViewImports.cshtmlでアプリに登録する必要はありません。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

活用事例

タグ ヘルパー コンポーネントの一般的なユース ケースには、次の 2 つがあります。

  1. <link><head>を挿入する。
  2. <script><body>を挿入する。

以降のセクションでは、これらのユース ケースについて説明します。

HTML ヘッド要素に挿入する

HTML <head> 要素内では、CSS ファイルは一般的に HTML <link> 要素と共にインポートされます。 次のコードでは、<link> タグ ヘルパー コンポーネントを使用して、<head>要素を head 要素に挿入します。

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

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

        public override int Order => 1;

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

            return Task.CompletedTask;
        }
    }
}

前のコードでは、次のようになります。

  • AddressStyleTagHelperComponent は、TagHelperComponent を実装します。 抽象化:
    • TagHelperContextを使用したクラスの初期化を許可します。
    • タグ ヘルパー コンポーネントを使用して HTML 要素を追加または変更できるようにします。
  • Orderプロパティは、コンポーネントをレンダリングする順序を定義します。 Order は、アプリでタグ ヘルパー コンポーネントを複数使用する場合に必要です。
  • ProcessAsync は、実行コンテキストの TagName プロパティ値を headと比較します。 比較が true と評価された場合、 _style フィールドの内容が HTML <head> 要素に挿入されます。

HTML 本文要素に挿入する

body タグ ヘルパー コンポーネントは、<script>要素を <body> 要素に挿入できます。 次のコードは、この手法を示しています。

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

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

<script>要素を格納するには、別の HTML ファイルが使用されます。 HTML ファイルを使用すると、コードがよりクリーンになり、保守が容易になります。 上記のコードは、 TagHelpers/Templates/AddressToolTipScript.html の内容を読み取り、タグ ヘルパー出力と共に追加します。 AddressToolTipScript.html ファイルには、次のマークアップが含まれています。

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

上記のコードは、ブートストラップ ツールヒント ウィジェットを、<address>属性を含む任意のprintable要素にバインドします。 効果は、マウス ポインターが要素の上に置くと表示されます。

コンポーネントの登録

タグ ヘルパー コンポーネントは、アプリのタグ ヘルパー コンポーネント コレクションに追加する必要があります。 コレクションに追加するには、次の 3 つの方法があります。

サービス コンテナーを使用した登録

タグ ヘルパー コンポーネント クラスが ITagHelperComponentManagerで管理されていない場合は、 依存関係挿入 (DI) システムに登録する必要があります。 次のStartup.ConfigureServicesコードは、AddressStyleTagHelperComponentAddressScriptTagHelperComponentクラスと クラスを登録します。

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

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

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

Razor ファイルを使用した登録

タグ ヘルパー コンポーネントが DI に登録されていない場合は、 Razor ページまたは MVC ビューから登録できます。 この手法は、挿入されたマークアップと、 Razor ファイルからのコンポーネントの実行順序を制御するために使用されます。

ITagHelperComponentManager は、タグ ヘルパー コンポーネントを追加したり、アプリから削除したりするために使用されます。 次のコードは、 AddressTagHelperComponentを使用したこの手法を示しています。

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

@{
    string markup;

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

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

前のコードでは、次のようになります。

  • @inject ディレクティブは、ITagHelperComponentManagerのインスタンスを提供します。 インスタンスは、manager ファイル内のダウンストリームにアクセスするために Razor という名前の変数に割り当てられます。
  • AddressTagHelperComponentのインスタンスがアプリのタグ ヘルパー コンポーネント コレクションに追加されます。

AddressTagHelperComponent は、 markup パラメーターと order パラメーターを受け入れるコンストラクターに対応するように変更されます。

private readonly string _markup;

public override int Order { get; }

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

指定された markup パラメーターは、 ProcessAsync で次のように使用されます。

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

ページ モデルまたはコントローラーを使用した登録

タグ ヘルパー コンポーネントが DI に登録されていない場合は、 Razor Pages ページ モデルまたは MVC コントローラーから登録できます。 この手法は、C# ロジックを Razor ファイルから分離する場合に役立ちます。

コンストラクターの挿入は、 ITagHelperComponentManagerのインスタンスにアクセスするために使用されます。 タグ ヘルパー コンポーネントがインスタンスのタグ ヘルパー コンポーネント コレクションに追加されます。 次の Razor Pages ページ モデルは、 AddressTagHelperComponentでこの手法を示しています。

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

public class IndexModel : PageModel
{
    private readonly ITagHelperComponentManager _tagHelperComponentManager;

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

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

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

    public void OnGet()
    {
        string markup;

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

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

前のコードでは、次のようになります。

  • コンストラクターの挿入は、 ITagHelperComponentManagerのインスタンスにアクセスするために使用されます。
  • AddressTagHelperComponentのインスタンスがアプリのタグ ヘルパー コンポーネント コレクションに追加されます。

コンポーネントを作成する

カスタム タグ ヘルパー コンポーネントを作成するには:

次のコードは、 <address> HTML 要素を対象とするカスタム タグ ヘルパー コンポーネントを作成します。

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

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

カスタム address タグ ヘルパー コンポーネントを使用して、次のように HTML マークアップを挿入します。

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

    public override int Order => 3;

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

上記のProcessAsyncメソッドは、提供されたSetHtmlContentのHTMLを一致する<address>要素に挿入します。 インジェクションは、次の場合に発生します。

  • 実行コンテキストの TagName プロパティ値は、 addressと等しくなります。
  • 対応する <address> 要素には、 printable 属性があります。

たとえば、次のif要素を処理すると、<address> ステートメントは true に評価されます。

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

その他のリソース