Accueil Nos publications Blog [ASP.NET MVC 6] Introduction aux Tags Helpers

[ASP.NET MVC 6] Introduction aux Tags Helpers

ASP.NET logoLe fait d’utiliser deux langages dans un même fichier de code peut se révéler être un véritable défi à l’écriture, à la lecture et donc à la compréhension du contenu de ce fichier. C’est d’autant plus le cas si les deux sont langages sont tous les deux basés sur des grammaires radicalement différentes. Les Tag Helpers sont un mécanisme d’ASP.NET MVC 6 dont le but est de répondre à cette problématique.

La problématique historique

Dans le cas de vues Razor, les développeurs mixent allègrement HTML, un langage de balisage qui décrit la structure d’une page, avec du code C# ou Visual Basic, qui permettent de faire exécuter des instructions par le serveur. Ces deux syntaxes ne sont pas forcément évidentes à faire cohabiter, et cela se corse encore plus lorsqu’il est nécessaire d’exprimer en C# des éléments qui s’expriment en temps normal avec HTML.

L’exemple ci-dessous représente le problème qui vient d’être évoqué. Les parseurs utilisés par Razor savent facilement passer de C# à HTML en analysant la présence d’un signe arobase ou de balises. Pourtant, dans le cas ci-dessous, le HTML Helper TextBoxFor contient un élément de style important : une classe HTML qui est censée être utilisée pour appliquer un style à l’élément input généré.

<div class="form-group">
    @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
    <div class="col-md-10">
        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
    </div>
</div>

Cette situation est d’autant plus perturbante pour un néophyte du langage C# que le terme class est un mot clé réservé et inutilisable directement. Il doit être obligatoire précédé d’un sigle arobase pour que l’étape de compilation de la vue se termine avec succès.

L’exemple ci-dessous est une variante du précédent. Cette fois ci, il est nécessaire de faire porter à l’élément input divers attributs data. Ces derniers permettent d’ajouter des informations fonctionnelles à des éléments du DOM. Une autre particularité de C# est d’interdire l’utilisation du tiret dans le nom d’une propriété. Pour rendre ce cas de figure fonctionnel, il est nécessaire d’abandonner la syntaxe utilisant un objet anonyme et de passer par un dictionnaire dont les clés sont des chaînes de caractères.

<div class="form-group">
    @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
    <div class="col-md-10">
        @Html.TextBoxFor(m => m.UserName, new RouteValueDictionary() { { "data-input-mode", "free" } })
    </div>
</div>

Ce deuxième cas de figure est un bon exemple de la complexité de lecture et d’écriture rencontrée dans le développement de certains projets. Le problème est encore plus important lorsque des intégrateurs graphiques, qui n’ont généralement pas de compétence en C#, doivent directement éditer le code des vues. Ils ignorent généralement ces règles du langage et sont bloqués dans leur travail.

Référencer les Tags Helpers

Pour toutes ces raisons, les ingénieurs de Microsoft ont développé une nouvelle fonctionnalité dont le but est de simplifier et d’alléger l’écriture de vues avec Razor. Cette solution est nommée Tag Helpers.
Il s’agit en fait d’extensions de la syntaxe HTML qui sont interprétés directement par Razor, c’est-à-dire côté serveur. Ces extensions déclenchent alors une modification de la balise sur laquelle elles sont appliquées ; ou même la création et l’ajout de nouvelles balises dans le DOM. Les développeurs peuvent même y voir un moyen de créer l’équivalent de contrôles comme ils pouvaient le faire auparavant avec ASP.NET WebForms.

La notion de TagHelper est directement implémentée au niveau de Razor, c’est-à-dire au niveau du paquet Microsoft.AspNet.Razor. L’ajout de ce seul paquet vous donne accès à un nouveau mot-clé de la syntaxe Razor, @addtaghelper. Celui-ci doit s’utiliser conjointement avec un nom de paquet, c’est-à-dire le paquet dans lequel les Tag Helpers doivent être recherchés pour pouvoir être utilisables dans une vue.

Concrètement, pour utiliser des Tag Helpers créés dans un paquet MonEntreprise.Framework.Mvc, alors il faut ajouter l’instruction ci-dessous dans les vues qui doivent en faire usage, ou directement dans un fichier tel que _Layout.cshtml si l’usage concerne plusieurs vues. En optant pour une déclaration de la vue, la déclaration @addtaghelper doit obligatoirement se trouver après l’instruction @model.

@addtaghelper "MonEntreprise.Framework.Mvc"

Microsoft met à la disposition une série de Tag Helpers remplaçant le comportement par défaut des HTML Helpers les plus basiques tels que TextBoxFor ou ValidationSummary par exemple. Pour pouvoir les utiliser, il est nécessaire d’ajouter une référence vers le paquet Microsoft.AspNet.Mvc.TagHelpers dans le fichier project.json puis d’utiliser l’instruction suivante.

@addtaghelper "Microsoft.AspNet.Mvc.TagHelpers"

Utiliser les Tags Helpers

Une fois cet ajout réalisé, il est possible de remplacer la plupart des HTML Helpers présents dans une vue par des Tag Helpers. Pour commencer, un appel à TextBoxFor tel qu’il a été présenté un peu plus tôt peut s’écrire de la manière suivante :

<div class="col-md-10">
    <input type="text" for="UserName" class="form-control" />
</div>

Il y a deux éléments importants à noter ici. Dans un premier temps, il n’y a plus de changement syntaxique entre HTML et C# comme c’était le cas auparavant, ici seul le HTML est utilisé. Dans le cas de l’attribut class, le gain apporté par cette syntaxe est évident : un intégrateur peut venir modifier la structure et les classes présentes sur le DOM sans avoir aucune connaissance de C#. Il reste constamment dans un environnement qu’il connaît.

Dans un second temps, les développeurs les plus familiers de la syntaxe de HTML remarqueront qu’un attribut supplémentaire a fait son apparition sur la balise input. Il s’agit de l’attribut for. C’est cet attribut qui permet de faire la liaison entre la balise générée et le modèle. Automatiquement, Razor est capable de faire le lien avec le modèle passé en paramètre de la vue, et ce notamment afin d’attribuer la bonne valeur à la balise, mais aussi afin de générer les bons attributs de validation. Comme pour un usage classique des HTML Helpers, ces validateurs sont déduits à partir des attributs d’annotations placés sur la classe C# du modèle et ils permettent d’activer une validation des données côté JavaScript.

Ainsi, l’exemple précédent permet de générer la sortie suivante. Seul ce contenu HTML sera téléchargé dans le navigateur du client. L’attribut for a automatiquement été supprimé car il n’est utile qu’à Razor pour faire le lien avec le modèle.

<input class="form-control" data-val="true" data-val-required="The User name field is required." id="UserName" name="UserName" value="" type="text"></input>

Selon les balises HTML, les attributs Tag Helpers utilisables peuvent varier légèrement. Par exemple, dans le cas de la balise label, l’attribut for est un attribut compris nativement par le navigateur. Pour éviter les conflits et faciliter la compréhension des développeurs, l’attribut Tag Helper qu’il faut utiliser dans ce cas précis est l’attribut asp-for.

<label asp-for="UserName" class="control-label col-md-2" style="color:blue" />

L’utilisation de cet exemple dans Visual Studio permet de mettre en évidence un autre avantage des Tag Helpers. En reprenant le contrôle sur l’émission de la balise HTML, le développeur écrit directement les classes qu’il souhaite appliquer à la balise et les éventuels styles spécifiques à cette balise. Si ces éléments sont exprimés en C#, le développeur perd toute aide à la saisie. Or, en les saisissant directement en HTML, Visual Studio et ses compléments tels que Web Essentials, assistent le développeur dans sa saisie avec diverses fonctionnalités (propositions de classes, pré visualisation d’un style, etc.).

Le cas du HTML Helper ValidationMessageFor est assez similaire. Le Tag Helper à utiliser dans ce cas précis est asp-validation-for. D’une manière générale, tous les Tag Helpers proposés par Microsoft sont préfixés par le terme asp.

<span asp-validation-for="UserName" style="color:blue" />

Le cas ci-dessous illustre un formulaire complet qui peut être rencontré dans n’importe quelle application développée avec ASP.NET MVC. Les éléments remarquables de cet exemple se situent sur les balises form et sur la balise div à laquelle a été joint l’attribut asp-validation-summary. Dans le cas de la première, on constate que plusieurs attributs Tag Helper sont présents, et notamment l’attribut asp-action. C’est ce dernier qui va permettre la sélection de l’url à générer pour la cible du formulaire. Le Tag Helper est alors capable de faire appel à la table de routage pour chercher une action nommée Create sur le contrôleur courant. Si le développeur veut cibler une action d’un autre contrôleur, il lui suffit alors d’ajouter un attribut asp-controller.

<form asp-anti-forgery="false" asp-action="Create">
    <div class="form-horizontal">
        <div asp-validation-summary="ValidationSummary.All" style="color:blue" id="validation_day" class="form-group">
            <span style="color:red">Votre saisie contient des erreurs</span>
        </div>

        <div class="form-group">
            <label asp-for="Name" class="control-label col-md-2" style="color:blue" />
            <div class="col-md-10">
                <input type="text" asp-for="Name" style="color:blue" />
                <span asp-validation-for="Name" style="color:blue" />
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>

Au même titre qu’il était auparavant possible pour un développeur de créer ses propres HTML Helpers, il est maintenant possible de créer des Tag Helpers personnalisés. Ce processus passe d’abord par la création d’une classe héritant de la classe TagHelper. Cette dernière est abstraite et impose la déclaration d’une méthode ProcessAsync. C’est tout simplement cette méthode qui va contenir la logique du traitement du Tag Helper. Dans la plupart des cas, le développeur y analyse la présence d’attribut (par exemple asp-for ou asp-validation-summary pour les Tag Helpers standards) et y réagit en modifiant la balise courante ou en en générant de nouvelles.

Conclusion

Les Tags Helpers d’ASP.NET MVC 6 devraient changer l’opinion des derniers développeurs encore réticents face à la syntaxe de Razor. Grâce à ce mécanisme, le contenu des vues gagne en clarté et la sémantique est à nouveau utilisable par un intégrateur novice en C#. Dans un prochain billet, je reviendrai sur l’extensibilité des Tags Helpers et notamment la création de contrôles personnalisés.