Disposition dans ASP.NET Core

Article rédigé par Steve Smith et Dave Brock

Les pages et les vues ont souvent des éléments visuels et programmatiques en commun. Cet article montre comment :

  • Utiliser des dispositions communes.
  • Partager des directives.
  • Exécuter du code commun avant d’afficher des pages ou des vues.

Ce document traite des dispositions pour les deux approches différentes d’ASP.NET Core MVC : Razor Pages et les contrôleurs avec Vues. Pour cette rubrique, les différences sont minimes :

  • Les PagesRazor se trouvent dans le dossier Pages.
  • Les contrôleurs avec vues utilisent un dossier Views pour les vues.

Qu’est-ce qu’une disposition ?

La plupart des applications web ont une disposition commune pour offrir aux utilisateurs une expérience homogène quand ils naviguent de page en page. En général, la disposition inclut des éléments d’interface utilisateur communs à toute l’application, tels que l’en-tête, des éléments de menu ou de navigation et le pied de page.

Page Layout example

Les structures HTML courantes, comme les scripts et les feuilles de style, sont également fréquemment utilisées par de nombreuses pages dans une application. Tous ces éléments partagés peuvent être définis dans un fichier de disposition, qui peut ensuite être référencé par n’importe quelle vue utilisée dans l’application. Les dispositions réduisent la duplication de code dans les vues.

Par convention, la disposition par défaut d’une application ASP.NET Core se nomme _Layout.cshtml. Les fichiers de disposition pour les projets ASP.NET Core créés avec les modèles sont les suivants :

  • Razor Pages: Pages/Shared/_Layout.cshtml

    Pages folder in Solution Explorer

  • Contrôleur avec vues :Views/Shared/_Layout.cshtml

    Views folder in Solution Explorer

La disposition définit un modèle général pour les vues dans l’application. Les applications n’ont pas besoin d’une disposition. Elles peuvent définir plusieurs dispositions, avec des vues différentes spécifiant des dispositions différentes.

Le code suivant montre le fichier de disposition pour un projet créé avec un modèle, avec un contrôleur et des vues :

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - WebApplication1</title>

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
        <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
    </environment>
</head>
<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a asp-page="/Index" class="navbar-brand">WebApplication1</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a asp-page="/Index">Home</a></li>
                    <li><a asp-page="/About">About</a></li>
                    <li><a asp-page="/Contact">Contact</a></li>
                </ul>
            </div>
        </div>
    </nav>

    <partial name="_CookieConsentPartial" />

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; 2018 - WebApplication1</p>
        </footer>
    </div>

    <environment include="Development">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    </environment>
    <environment exclude="Development">
        <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.min.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
                asp-fallback-test="window.jQuery"
                crossorigin="anonymous"
                integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT">
        </script>
        <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
                crossorigin="anonymous"
                integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa">
        </script>
        <script src="~/js/site.min.js" asp-append-version="true"></script>
    </environment>

    @RenderSection("Scripts", required: false)
</body>
</html>

Spécification d’une disposition

Les vuesRazoront une propriété Layout. Chaque vue spécifie une disposition en définissant cette propriété :

@{
    Layout = "_Layout";
}

La disposition spécifiée peut utiliser un chemin complet (par exemple, /Pages/Shared/_Layout.cshtml ou /Views/Shared/_Layout.cshtml ) ou un nom partiel (par exemple, _Layout). Quand un nom partiel est fourni, le moteur de vue Razor recherche le fichier de disposition en utilisant son processus de détection habituel. Le dossier où se trouve la méthode de gestionnaire (ou contrôleur) est parcouru en premier, suivi du dossier Shared. Ce processus de détection est le même que celui utilisé pour détecter les vues partielles.

Par défaut, chaque disposition doit appeler RenderBody. À chaque appel de RenderBody, le contenu de la vue est affiché.

Sections

Une disposition peut éventuellement faire référence à une ou plusieurs sections, en appelant RenderSection. Les sections sont un moyen d’organiser certains éléments dans la page. Chaque appel à RenderSection peut spécifier si cette section est obligatoire ou facultative :

<script type="text/javascript" src="~/scripts/global.js"></script>

@RenderSection("Scripts", required: false)

Si une section obligatoire est introuvable, une exception est levée. Chacune des vues individuelles spécifie le contenu à afficher dans une section à l’aide de la syntaxe @sectionRazor. Si une page ou vue définit une section, elle doit être affichée (sinon, une erreur se produit).

Exemple de définition @section dans une vue Razor Pages :

@section Scripts {
     <script type="text/javascript" src="~/scripts/main.js"></script>
}

Dans le code précédent, scripts/main.js est ajouté à la section scripts sur une page ou vue. Il est possible que les autres pages ou vues de la même application ne nécessitent pas ce script et ne définissent pas de section de scripts.

Le balisage suivant utilise l’assistance partielle de balisage pour afficher _ValidationScriptsPartial.cshtml :

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Le balisage précédent était le résultat de la génération d’un modèle automatiqueIdentity.

Les sections définies dans une page ou vue sont disponibles uniquement dans sa page de disposition la plus proche. Elles ne peuvent pas être référencées à partir de vues partielles, de composants de vue ou d’autres parties du système de vue.

Ignorer des sections

Par défaut, le corps et toutes les sections dans une page de contenu doivent intégralement être affichés par la page de disposition. Le moteur de vue Razor s’assure que c’est bien le cas en vérifiant que le corps et que chaque section ont été affichés.

Pour indiquer au moteur de vue d’ignorer le corps ou les sections, appelez les méthodes IgnoreBody et IgnoreSection.

Le corps et toutes les sections dans une page Razordoivent être soit affichés, soit ignorés.

Importation de directives partagées

Les vues et les pages peuvent utiliser des directives Razor pour importer des espaces de noms et utiliser l’injection de dépendances. Les directives partagées par plusieurs vues peuvent être spécifiées dans un fichier _ViewImports.cshtml commun. Le fichier _ViewImports prend en charge les directives suivantes :

  • @addTagHelper
  • @removeTagHelper
  • @tagHelperPrefix
  • @using
  • @model
  • @inherits
  • @inject
  • @namespace

Le fichier ne prend pas en charge les autres fonctionnalités Razor, telles que les fonctions et les définitions de section.

Exemple de fichier _ViewImports.cshtml :

@using WebApplication1
@using WebApplication1.Models
@using WebApplication1.Models.AccountViewModels
@using WebApplication1.Models.ManageViewModels
@using Microsoft.AspNetCore.Identity
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Le fichier _ViewImports.cshtml_ViewImports.cshtml pour une application ASP.NET Core MVC est généralement créé dans le dossier Pages (ou Vues). Un fichier _ViewImports.cshtml peut être créé dans un autre dossier, auquel cas il s’applique uniquement aux vues contenues dans ce dossier et ses sous-dossiers. Les fichiers _ViewImports sont traités à partir de la racine, puis pour chaque dossier conduisant à l’emplacement de la page ou vue elle-même. Les paramètres _ViewImports spécifiés au niveau de la racine peuvent être remplacés au niveau du dossier.

Par exemple, supposons que :

  • Le niveau racine du fichier_ViewImports.cshtml inclut @model MyModel1 et @addTagHelper *, MyTagHelper1.
  • Un fichier de sous-dossier_ViewImports.cshtml inclut @model MyModel2 et @addTagHelper *, MyTagHelper2.

Les pages et vues dans le sous-dossier ont accès aux Tag Helpers et au modèle MyModel2.

Si de multiples fichiers _ViewImports.cshtml se trouvent dans la hiérarchie des fichiers, le comportement combiné des directives est le suivant :

  • @addTagHelper, @removeTagHelper : les deux directives sont exécutées, dans l’ordre
  • @tagHelperPrefix : la directive la plus proche de la vue se substitue aux autres
  • @model : la directive la plus proche de la vue se substitue aux autres
  • @inherits : la directive la plus proche de la vue se substitue aux autres
  • @using : toutes les directives sont incluses ; les doublons sont ignorés
  • @inject : pour chaque propriété, la plus proche de la vue se substitue aux autres propriétés ayant le même nom

Exécution du code avant chaque vue

Le code qui doit s’exécuter avant chaque vue ou page doit être placé dans le fichier _ViewStart.cshtml. Par convention, le fichier _ViewStart.cshtml se trouve dans le dossier Pages (ou Vues ). Les instructions contenues dans _ViewStart.cshtml sont exécutées avant chaque vue complète (donc hors dispositions et vues partielles). Comme ViewImports.cshtml, _ViewStart.cshtml a une structure hiérarchique. Si un fichier _ViewStart.cshtmlst défini dans le dossier des vues ou des pages, il est exécuté après celui qui est défini à la racine du dossier Pages (ou Vues) le cas échéant.

Exemple de fichier _ViewStart.cshtml :

@{
    Layout = "_Layout";
}

Le fichier ci-dessus spécifie que toutes les vues doivent utiliser la disposition _Layout.cshtml.

_ViewStart.cshtml et _ViewImports.cshtmlne sont pas généralement placés dans le dossier /Pages/Partagé (ou/Vues/Partagé). Les versions de ces fichiers qui sont au niveau de l’application doivent être placées directement dans le dossier /Pages (ou /Views).