Partager via


Composants Tag Helper dans ASP.NET Core

Par Scott Addie et Fiyaz Bin Hasan

Un composant Tag Helper est un Tag Helper qui permet de modifier ou d’ajouter des éléments HTML de manière conditionnelle à partir du code côté serveur. Cette fonctionnalité est disponible dans ASP.NET Core 2.0 ou version ultérieure.

ASP.NET Core comprend deux composants Tag Helper intégrés : head et body. Ils sont situés dans l'espace de noms Microsoft.AspNetCore.Mvc.Razor.TagHelpers et peuvent être utilisés tant dans les applications MVC que dans les pages Razor. Les composants Tag Helper ne nécessitent pas d’inscription auprès de l’application dans _ViewImports.cshtml.

Afficher ou télécharger un exemple de code (comment télécharger)

Cas d’utilisation

Deux cas d’usage courants des composants Tag Helper sont les suivants :

  1. Injecter un <link> dans le <head>.
  2. Injecter un <script> dans le <body>.

Les sections suivantes décrivent ces cas d’usage.

Injecter dans l’élément head HTML

À l’intérieur de l’élément HTML <head> , les fichiers CSS sont généralement importés avec l’élément HTML <link> . Le code suivant injecte un <link> élément dans l’élément à l’aide <head> du head composant Tag Helper :

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

Dans le code précédent :

  • L'objet AddressStyleTagHelperComponent implémente l'objet TagHelperComponent. Abstraction :
    • Autorise l’initialisation de la classe avec un TagHelperContext.
    • Permet d’utiliser les composants Tag Helper pour ajouter ou modifier des éléments HTML.
  • La Order propriété définit l’ordre dans lequel les composants sont rendus. Order est nécessaire lorsqu’il existe plusieurs utilisations des composants Tag Helper dans une application.
  • ProcessAsync compare la valeur de propriété du contexte d’exécution TagName à head. Si la comparaison prend la valeur true, le contenu du _style champ est injecté dans l’élément HTML <head> .

Injecter dans l’élément corps HTML

Le body composant Tag Helper peut injecter un <script> élément dans l’élément <body> . Le code suivant illustre cette technique :

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

Un fichier HTML distinct est utilisé pour stocker l’élément <script> . Le fichier HTML rend le code plus propre et plus facile à gérer. Le code précédent lit le contenu de TagHelpers/Templates/AddressToolTipScript.html et l'ajoute à la sortie Tag Helper. Le AddressToolTipScript.html fichier inclut le balisage suivant :

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

Le code précédent lie un widget d’info-bulle Bootstrap à n’importe quel <address> élément qui inclut un printable attribut. L’effet est visible lorsqu’un pointeur de souris pointe sur l’élément.

Inscrire un composant

Un composant Tag Helper doit être ajouté à la collection Tag Helper Components de l’application. Il existe trois façons d’ajouter à la collection :

Inscription via le conteneur de services

Si la classe Tag Helper Component n’est pas gérée avec ITagHelperComponentManager, elle doit être inscrite auprès du système d’injection de dépendances (DI). Le code suivant Startup.ConfigureServices inscrit les AddressStyleTagHelperComponent et les AddressScriptTagHelperComponent classes avec une durée de vie transitoire :

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

Inscription via Razor un fichier

Si le composant Tag Helper n’est pas inscrit à l’aide de l’interface de connexion, il peut être inscrit à partir d’une page Pages ou d’une Razor vue MVC. Cette technique est utilisée pour contrôler le balisage injecté et l’ordre d’exécution du composant à partir d’un Razor fichier.

ITagHelperComponentManager est utilisé pour ajouter des composants Tag Helper ou les supprimer de l’application. Le code suivant illustre cette technique avec 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));
}

Dans le code précédent :

  • La @inject directive fournit une instance de ITagHelperComponentManager. L’instance est affectée à une variable nommée manager pour l’accès en aval dans le Razor fichier.
  • Une instance de AddressTagHelperComponent est ajoutée à la collection de composants Tag Helper de l'application.

AddressTagHelperComponent est modifié pour qu'il prenne en charge un constructeur qui accepte les paramètres markup et order.

private readonly string _markup;

public override int Order { get; }

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

Le paramètre fourni markup est utilisé dans ProcessAsync comme suit :

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

Inscription via le modèle de page ou le contrôleur

Si le composant Tag Helper n’est pas inscrit à l’aide de l’interface de domaine, il peut être inscrit à partir d’un Razor modèle de page Pages ou d’un contrôleur MVC. Cette technique est utile pour séparer la logique C# des Razor fichiers.

L’injection de constructeur est utilisée pour accéder à une instance de ITagHelperComponentManager. Le composant Tag Helper est ajouté à la collection Tag Helper Components de l’instance. Le modèle de pages suivant Razor démontre cette technique avec 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));
    }
}

Dans le code précédent :

  • L’injection de constructeur est utilisée pour accéder à une instance de ITagHelperComponentManager.
  • Une instance de AddressTagHelperComponent est ajoutée à la collection de composants Tag Helper de l'application.

Créer un composant

Pour créer un composant Tag Helper personnalisé :

Le code suivant crée un composant Tag Helper personnalisé qui cible l’élément <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)
        {
        }
    }
}

Utilisez le composant Tag Helper personnalisé address pour injecter le balisage HTML comme suit :

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

La méthode précédente ProcessAsync injecte le code HTML fourni SetHtmlContent dans l’élément correspondant <address> . L’injection se produit quand :

  • La valeur de propriété du contexte d’exécution TagName est égale address.
  • L’élément correspondant <address> a un printable attribut.

Par exemple, l’instruction if prend la valeur true lors du traitement de l’élément suivant <address> :

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

Ressources supplémentaires