Layout in ASP.NET CoreLayout in ASP.NET Core

Di Steve Smith e Dave BrockBy Steve Smith and Dave Brock

Le pagine e le visualizzazioni condividono spesso elementi visivi e programmatici.Pages and views frequently share visual and programmatic elements. Questo articolo illustra come effettuare le seguenti operazioni:This article demonstrates how to:

  • Usare layout comuni.Use common layouts.
  • Condividere direttive.Share directives.
  • Eseguire codice comune prima del rendering di pagine o visualizzazioni.Run common code before rendering pages or views.

Questo documento illustra i layout per i due diversi approcci per ASP.NET Core MVC: Razor Pages e controller con visualizzazioni.This document discusses layouts for the two different approaches to ASP.NET Core MVC: Razor Pages and controllers with views. Per questo argomento le differenze siano minime:For this topic, the differences are minimal:

  • Le pagine Razor Pages sono disponibili nella cartella Pages.Razor Pages are in the Pages folder.
  • I controller con visualizzazioni usano una cartella Views per le visualizzazioni.Controllers with views uses a Views folder for views.

Che cos'è il layout?What is a Layout

La maggior parte delle applicazioni web presenta un layout comune che fornisce all'utente un'esperienza omogenea, nel passare da una pagina a un'altra.Most web apps have a common layout that provides the user with a consistent experience as they navigate from page to page. In genere, il layout comprende elementi dell'interfaccia utente comune, ad esempio l'intestazione dell'app, la navigazione o elementi di menu e piè di pagina.The layout typically includes common user interface elements such as the app header, navigation or menu elements, and footer.

Esempio di layout di pagina

Molte pagine all'interno di un'app utilizzano anche strutture HTML comuni, come script e fogli di stile.Common HTML structures such as scripts and stylesheets are also frequently used by many pages within an app. Tutti questi elementi condivisi possono essere definiti in un file di layout, cui è possibile fare riferimento da qualsiasi visualizzazione utilizzata all'interno dell'app.All of these shared elements may be defined in a layout file, which can then be referenced by any view used within the app. I layout riducono il codice duplicato nelle visualizzazioni.Layouts reduce duplicate code in views.

Per convenzione, il layout predefinito per un'app ASP.NET Core è denominato _Layout.cshtml.By convention, the default layout for an ASP.NET Core app is named _Layout.cshtml. I file di layout per i nuovi progetti ASP.NET Core creati con i modelli sono:The layout files for new ASP.NET Core projects created with the templates are:

  • Razor Pages: Pages/Shared/_Layout.cshtmlRazor Pages: Pages/Shared/_Layout.cshtml

    Cartella Pages in Esplora soluzioni

  • Controller con visualizzazioni: Views/Shared/_Layout.cshtmlController with views: Views/Shared/_Layout.cshtml

    Cartella Views in Esplora soluzioni

Il layout definisce un modello di primo livello per le visualizzazioni nell'app.The layout defines a top level template for views in the app. Le app non richiedono un layout.Apps don't require a layout. Le app possono definire più di un layout, con visualizzazioni diverse che specificano layout differenti.Apps can define more than one layout, with different views specifying different layouts.

Il codice seguente mostra il file di layout per un progetto creato da modello con un controller e visualizzazioni:The following code shows the layout file for a template created project with a controller and views:

<!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>

Definizione di un layoutSpecifying a Layout

Le visualizzazioni Razor hanno una proprietà Layout.Razor views have a Layout property. Le visualizzazioni singole specificano un layout impostando la seguente proprietà:Individual views specify a layout by setting this property:

@{
    Layout = "_Layout";
}

Il layout specificato può usare un percorso completo (ad esempio, /Pages/Shared/_Layout.cshtml o /Views/Shared/_Layout.cshtml) oppure un nome parziale (ad esempio: _Layout).The layout specified can use a full path (for example, /Pages/Shared/_Layout.cshtml or /Views/Shared/_Layout.cshtml) or a partial name (example: _Layout). Quando viene fornito un nome parziale, il motore di visualizzazione Razor cerca il file di layout tramite il processo di individuazione standard.When a partial name is provided, the Razor view engine searches for the layout file using its standard discovery process. La ricerca viene eseguita prima nella cartella in cui è presente il metodo gestore (o controller) e poi nella cartella Shared.The folder where the handler method (or controller) exists is searched first, followed by the Shared folder. Questo processo di individuazione è identico a quello usato per individuare le visualizzazioni parziali.This discovery process is identical to the process used to discover partial views.

Per impostazione predefinita, ogni layout deve chiamare RenderBody.By default, every layout must call RenderBody. Quando viene eseguita la chiamata a RenderBody, viene eseguito il rendering del contenuto della visualizzazione.Wherever the call to RenderBody is placed, the contents of the view will be rendered.

SezioniSections

Un layout può facoltativamente fare riferimento a una o più sezioni, chiamando RenderSection.A layout can optionally reference one or more sections, by calling RenderSection. Le sezioni forniscono un modo per organizzare la posizione in cui devono essere inseriti determinati elementi di pagina.Sections provide a way to organize where certain page elements should be placed. Ogni chiamata a RenderSection può specificare se tale sezione è obbligatoria o facoltativa:Each call to RenderSection can specify whether that section is required or optional:

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

@RenderSection("Scripts", required: false)

Se una sezione richiesta non viene trovata, viene generata un'eccezione.If a required section isn't found, an exception is thrown. Le viste singole specificano il contenuto da sottoporre a rendering all'interno di una sezione tramite la sintassi Razor @section.Individual views specify the content to be rendered within a section using the @section Razor syntax. Se una pagina o una visualizzazione definisce una sezione, è necessario eseguirne il rendering (o si verifica un errore).If a page or view defines a section, it must be rendered (or an error will occur).

Definizione @section di esempio nella visualizzazione Razor Pages:An example @section definition in Razor Pages view:

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

Nel codice precedente, scripts/main.js viene aggiunto alla sezione scripts in una pagina o visualizzazione.In the preceding code, scripts/main.js is added to the scripts section on a page or view. Altre pagine o visualizzazioni nella stessa app potrebbero non richiedere questo script e non definire una sezione scripts.Other pages or views in the same app might not require this script and wouldn't define a scripts section.

Il markup seguente usa l'helper tag parziale per eseguire il rendering di _ValidationScriptsPartial.cshtml:The following markup uses the Partial Tag Helper to render _ValidationScriptsPartial.cshtml:

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

Il markup precedente è stato generato tramite scaffolding di Identity.The preceding markup was generated by scaffolding Identity.

Le sezioni definite in una pagina o in una visualizzazione sono disponibili solo nella relativa pagina di layout immediato.Sections defined in a page or view are available only in its immediate layout page. Non è possibile farvi riferimento da righe parzialmente eseguite, componenti di visualizzazione o altre parti del sistema di visualizzazione.They cannot be referenced from partials, view components, or other parts of the view system.

Esclusione di sezioniIgnoring sections

Per impostazione predefinita, la pagina di layout deve eseguire il rendering della parte principale e di tutte le sezioni di una pagina di contenuto.By default, the body and all sections in a content page must all be rendered by the layout page. Il motore di visualizzazione Razor impone questa operazione verificando se è stato eseguito il rendering della parte principale e di ogni sezione.The Razor view engine enforces this by tracking whether the body and each section have been rendered.

Per indicare al motore di visualizzazione di escludere la parte principale o le sezioni, chiamare i metodi IgnoreBody e IgnoreSection.To instruct the view engine to ignore the body or sections, call the IgnoreBody and IgnoreSection methods.

Deve essere eseguito il rendering della parte principale e di tutte le sezioni di una pagina Razor oppure devono essere escluse.The body and every section in a Razor page must be either rendered or ignored.

Importazione delle direttive condiviseImporting Shared Directives

Le visualizzazioni e le pagine possono usare direttive Razor per l'importazione di spazi dei nomi e usare l'inserimento delle dipendenze.Views and pages can use Razor directives to importing namespaces and use dependency injection. Le direttive condivise da numerose visualizzazioni possono essere specificate in un file _ViewImports.cshtml comune.Directives shared by many views may be specified in a common _ViewImports.cshtml file. Il file _ViewImports supporta le direttive seguenti:The _ViewImports file supports the following directives:

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

Il file non supporta altre funzionalità di Razor, come le funzioni e le definizioni di sezione.The file doesn't support other Razor features, such as functions and section definitions.

Esempio di file _ViewImports.cshtml:A sample _ViewImports.cshtml file:

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

Il file _ViewImports.cshtml per un'app ASP.NET Core MVC viene generalmente posizionato nella cartella Pages (o Views).The _ViewImports.cshtml file for an ASP.NET Core MVC app is typically placed in the Pages (or Views) folder. È possibile posizionare un file _ViewImports.cshtml in qualsiasi cartella, nel qual caso verrà applicato unicamente alle pagine o alle visualizzazioni all'interno di tale cartella e nelle relative sottocartelle.A _ViewImports.cshtml file can be placed within any folder, in which case it will only be applied to pages or views within that folder and its subfolders. I file _ViewImports vengono elaborati a partire dal livello radice e quindi per ogni cartella fino alla posizione della pagina o della visualizzazione stessa._ViewImports files are processed starting at the root level and then for each folder leading up to the location of the page or view itself. Le impostazioni _ViewImports specificate al livello radice possono essere sottoposto a override a livello di cartella._ViewImports settings specified at the root level may be overridden at the folder level.

Si supponga ad esempio che:For example, suppose:

  • Il file _ViewImports.cshtml al livello radice includa @model MyModel1 e @addTagHelper *, MyTagHelper1.The root level _ViewImports.cshtml file includes @model MyModel1 and @addTagHelper *, MyTagHelper1.
  • Un file _ViewImports.cshtml in una sottocartella includa @model MyModel2 e @addTagHelper *, MyTagHelper2.A subfolder _ViewImports.cshtml file includes @model MyModel2 and @addTagHelper *, MyTagHelper2.

Le pagine e le visualizzazioni nella sottocartella avranno accesso sia agli helper tag che al modello MyModel2.Pages and views in the subfolder will have access to both Tag Helpers and the MyModel2 model.

Se vengono trovati più file _ViewImports.cshtml nella gerarchia di file, il comportamento combinato delle direttive è il seguente:If multiple _ViewImports.cshtml files are found in the file hierarchy, the combined behavior of the directives are:

  • @addTagHelper, @removeTagHelper: eseguiti nell'ordine@addTagHelper, @removeTagHelper: all run, in order
  • @tagHelperPrefix: il file più vicino alla visualizzazione esegue l'override di tutti gli altri@tagHelperPrefix: the closest one to the view overrides any others
  • @model: il file più vicino alla visualizzazione esegue l'override di tutti gli altri@model: the closest one to the view overrides any others
  • @inherits: il file più vicino alla visualizzazione esegue l'override di tutti gli altri@inherits: the closest one to the view overrides any others
  • @using: vengono inclusi tutti; i duplicati vengono esclusi@using: all are included; duplicates are ignored
  • @inject: per ogni proprietà, quella più vicina alla visualizzazione esegue l'override di tutte le altre con lo stesso nome di proprietà@inject: for each property, the closest one to the view overrides any others with the same property name

Esecuzione di codice prima di ogni visualizzazioneRunning Code Before Each View

Il codice che deve essere eseguito prima di ogni visualizzazione o pagina deve essere posizionato nel file _ViewStart.cshtml.Code that needs to run before each view or page should be placed in the _ViewStart.cshtml file. Per convenzione, il file _ViewStart.cshtml si trova nella cartella Pages (o Views).By convention, the _ViewStart.cshtml file is located in the Pages (or Views) folder. Le istruzioni elencate in _ViewStart.cshtml vengono eseguite prima di ogni visualizzazione completa (non dei layout e delle visualizzazioni parziali).The statements listed in _ViewStart.cshtml are run before every full view (not layouts, and not partial views). Come ViewImports.cshtml, _ViewStart.cshtml è gerarchico.Like ViewImports.cshtml, _ViewStart.cshtml is hierarchical. Se un file _ViewStart.cshtml viene definito nella cartella delle visualizzazioni o delle pagine, verrà eseguito dopo quello definito nella radice della cartella Pages (o Views) (se presente).If a _ViewStart.cshtml file is defined in the view or pages folder, it will be run after the one defined in the root of the Pages (or Views) folder (if any).

File _ViewStart.cshtml di esempio:A sample _ViewStart.cshtml file:

@{
    Layout = "_Layout";
}

Il file precedente specifica che tutte le visualizzazioni useranno il layout _Layout.cshtml.The file above specifies that all views will use the _Layout.cshtml layout.

_ViewStart.cshtml e _ViewImports.cshtml non vengono in genere posizionati nella cartella /Pages/Shared (o /Views/Shared)._ViewStart.cshtml and _ViewImports.cshtml are not typically placed in the /Pages/Shared (or /Views/Shared) folder. Le versioni a livello di app di questi file devono essere posizionate direttamente nella cartella /Pages (o /Views).The app-level versions of these files should be placed directly in the /Pages (or /Views) folder.