Condividi tramite


Layout in ASP.NET Core

Di Steve Smith e Dave Brock

Le pagine e le visualizzazioni condividono spesso elementi visivi e programmatici. Questo articolo illustra come:

  • Usare layout comuni.
  • Direttive di condivisione.
  • Eseguire codice comune prima di eseguire il rendering di pagine o visualizzazioni.

Questo documento illustra i layout per i due diversi approcci a ASP.NET Core MVC: Razor Pagine e controller con visualizzazioni. Per questo argomento, le differenze sono minime:

  • Razor Le pagine si trovano nella cartella Pages .
  • I controller con visualizzazioni usano una cartella Views per le visualizzazioni.

Che cos'è un layout

La maggior parte delle app Web ha un layout comune che offre all'utente un'esperienza coerente durante la navigazione dalla pagina alla pagina. Il layout include in genere elementi comuni dell'interfaccia utente, ad esempio l'intestazione dell'app, gli elementi di spostamento o di menu e il piè di pagina.

Esempio di layout di pagina

Le strutture HTML comuni, ad esempio script e fogli di stile, vengono spesso usate da molte pagine all'interno di un'app. Tutti questi elementi condivisi possono essere definiti in un file di layout , a cui può quindi fare riferimento qualsiasi visualizzazione usata all'interno dell'app. I layout riducono il codice duplicato nelle visualizzazioni.

Per convenzione, il layout predefinito per un'app ASP.NET Core è denominato _Layout.cshtml. I file di layout per i nuovi progetti ASP.NET Core creati con i modelli sono:

  • Razor Pagine: Pages/Shared/_Layout.cshtml

    Cartella Pagine in Esplora soluzioni

  • Controller con visualizzazioni: Views/Shared/_Layout.cshtml

    Cartella Visualizzazioni in Esplora soluzioni

Il layout definisce un modello di primo livello per le visualizzazioni nell'app. Le app non richiedono un layout. Le app possono definire più layout, con visualizzazioni diverse che specificano layout diversi.

Il codice seguente mostra il file di layout per un progetto modello creato, che include un controller e delle view.

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

Specificare un layout

Razor visualizzazioni hanno una Layout proprietà. Le singole visualizzazioni specificano un layout impostando questa proprietà:

@{
    Layout = "_Layout";
}

Il layout specificato può usare un percorso completo (ad esempio, /Pages/Shared/_Layout.cshtml o ) o /Views/Shared/_Layout.cshtmlun nome parziale (ad esempio: _Layout). Quando viene specificato un nome parziale, il Razor motore di visualizzazione cerca il file di layout usando il processo di individuazione standard. La cartella in cui si trova il metodo del gestore (o il controller) viene cercata per prima, seguita dalla cartella Shared. Questo processo di individuazione è identico al processo usato per individuare visualizzazioni parziali.

Per impostazione predefinita, ogni layout deve chiamare RenderBody. Ovunque si trovi la chiamata a RenderBody , verrà eseguito il rendering del contenuto della visualizzazione.

Sezioni

Un layout può facoltativamente fare riferimento a una o più sezioni chiamando RenderSection. Le sezioni consentono di organizzare la posizione di determinati elementi di pagina. Ogni chiamata a RenderSection può specificare se la sezione è obbligatoria o facoltativa:

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

@RenderSection("Scripts", required: false)

Se non viene trovata una sezione obbligatoria, viene generata un'eccezione. Le singole visualizzazioni specificano il contenuto di cui eseguire il rendering all'interno di una sezione usando la @sectionRazor sintassi . Se una pagina o una vista definisce una sezione, è necessario eseguirne il rendering o si verificherà un errore.

Definizione di esempio @section nella Razor visualizzazione Pagine:

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

Nel codice precedente, scripts/main.js viene aggiunto alla sezione scripts di una pagina o di una vista. Altre pagine o visualizzazioni nella stessa app potrebbero non richiedere questo script e non definirerebbero una sezione degli script.

Il markup seguente usa il Partial Tag Helper per il rendering di _ValidationScriptsPartial.cshtml:

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

Il markup precedente è stato generato dallo scaffolding Identity.

Le sezioni definite in una pagina o in una vista sono disponibili solo nella pagina di layout immediato. Non è possibile farvi riferimento da parti parziali, componenti di visualizzazione o altre parti del sistema di visualizzazione.

Ignorare le sezioni

Per impostazione predefinita, il corpo e tutte le sezioni di una pagina di contenuto devono essere sottoposti a rendering dalla pagina di layout. Il Razor motore di visualizzazione applica questa impostazione verificando se è stato eseguito il rendering del corpo e di ogni sezione.

Per indicare al motore di visualizzazione di ignorare il corpo o le sezioni, chiamare i metodi IgnoreBody e IgnoreSection.

Il corpo e ogni sezione di una Razor pagina devono essere renderizzati o ignorati.

Importazione di direttive condivise

Le visualizzazioni e le pagine possono usare Razor direttive per importare i namespace e usare il dependency injection. Le direttive condivise da molte viste possono essere specificate in un file comune _ViewImports.cshtml . Il _ViewImports file supporta le direttive seguenti:

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

Il file non supporta altre Razor funzionalità, ad esempio funzioni e definizioni di sezione.

Un file di esempio _ViewImports.cshtml :

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

Il _ViewImports.cshtml file per un'app MVC core ASP.NET viene in genere inserito nella cartella Pages (o Views). Un _ViewImports.cshtml file può essere inserito all'interno di qualsiasi cartella, nel qual caso verrà applicato solo alle pagine o alle visualizzazioni all'interno di tale cartella e delle relative sottocartelle. _ViewImports i file vengono elaborati a partire dal livello radice e quindi per ogni cartella che conduce alla posizione della pagina o della visualizzazione stessa. _ViewImports le impostazioni specificate a livello radice possono essere sottoposte a override a livello di cartella.

Si supponga, ad esempio, di:

  • Il file a livello radice _ViewImports.cshtml include @model MyModel1 e @addTagHelper *, MyTagHelper1.
  • Un file nella sottocartella _ViewImports.cshtml include @model MyModel2 e @addTagHelper *, MyTagHelper2.

Le pagine e le visualizzazioni nella sottocartella avranno accesso sia ai Tag Helper che al modello MyModel2.

Se nella gerarchia dei file vengono trovati più _ViewImports.cshtml file, il comportamento combinato delle direttive è:

  • @addTagHelper, @removeTagHelper: tutte le esecuzioni, in ordine
  • @tagHelperPrefix: quello più vicino alla vista sovrascrive tutti gli altri
  • @model: quello più vicino nella visualizzazione sovrascrive qualsiasi altro
  • @inherits: quello più vicino alla vista sovrascrive tutti gli altri
  • @using: tutti sono inclusi; i duplicati vengono ignorati
  • @inject: per ogni proprietà, quella più vicina alla visualizzazione esegue l'override di qualsiasi altra proprietà con lo stesso nome di proprietà

Esecuzione del codice prima di ogni visualizzazione

Codice che deve essere eseguito prima che ogni visualizzazione o pagina venga inserita nel _ViewStart.cshtml file. Per convenzione, il _ViewStart.cshtml file si trova nella cartella Pages (o Views). Le istruzioni elencate in _ViewStart.cshtml vengono eseguite prima di ogni visualizzazione completa (non layout e non visualizzazioni parziali). Come ViewImports.cshtml, _ViewStart.cshtml è gerarchico. Se un _ViewStart.cshtml file viene definito nella cartella di visualizzazione o pagine, verrà eseguito dopo quello definito nella radice della cartella Pages (o Views) (se presente).

Un file di esempio _ViewStart.cshtml :

@{
    Layout = "_Layout";
}

Il file precedente specifica che tutte le visualizzazioni useranno il _Layout.cshtml layout.

_ViewStart.cshtml e _ViewImports.cshtmlnon vengono in genere inseriti nella cartella /Pages/Shared (o /Views/Shared). Le versioni a livello di app di questi file devono essere inserite direttamente nella cartella /Pages (o /Views).