Layout in ASP.NET Core

Von Steve Smith und Dave Brock

Seiten und Ansichten beinhalten häufig sowohl visuelle als auch programmgesteuerte Elemente. Dieser Artikel demonstriert Folgendes:

  • Verwendung von allgemeinen Layouts
  • Freigeben von Anweisungen
  • Führen Sie den allgemeinen Code aus, bevor Sie Seiten oder Ansichten rendern.

In diesem Dokument werden Layouts für zwei verschiedene Ansätze zu ASP.NET Core MVC erläutert: Razor Pages und Controller mit Ansichten. In diesem Thema sind die Unterschiede minimal:

  • Razor Pages befindet sich im Ordner Pages.
  • Controller mit Ansichten verwenden einen Ordner namens Views für Ansichten.

Was ist ein Layout?

Die meisten Web-Apps haben ein gebräuchliches Layout, das dem Benutzer beim Navigieren auf den Seiten ein konsistentes Verhalten bietet. Das Layout enthält normalerweise allgemeine Benutzeroberflächenelemente wie App-Header, Navigations- oder Menüelemente sowie eine Fußzeile.

Page Layout example

Oft verwendete HTML-Strukturen wie Skripts und Stylesheets werden auch häufig von vielen Seiten in einer App genutzt. Alle diese gemeinsamen Elemente werden in einer Layoutdatei definiert, auf die dann von jeder Ansicht einer App verwiesen werden kann. Layouts verringern Codeduplikate in Ansichten.

Gemäß Konvention ist _Layout.cshtml das Standardlayout für eine ASP.NET Core-App. Für neue ASP.NET Core-Projekte, die mit den Vorlagen erstellt wurden, sind folgende Layoutdateien vorhanden:

  • Razor Pages: Pages/Shared/_Layout.cshtml

    Pages folder in Solution Explorer

  • Controller mit Ansichten: Views/Shared/_Layout.cshtml

    Views folder in Solution Explorer

Das Layout definiert eine übergeordnete Vorlage für die Ansichten einer App. Für Apps ist kein Layout erforderlich. Sie können allerdings mehrere Layouts mit unterschiedlichen Ansichten aufweisen.

Der folgende Code zeigt die Layoutdatei für eine Vorlage, die mit dem Projekt mit einem Controller und Ansichten erstellt wurde:

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

Festlegen eines Layouts

Razor-Ansichten verfügen über eine Layout-Eigenschaft. Durch Festlegen dieser Eigenschaft wird das Layout der jeweiligen Ansicht bestimmt:

@{
    Layout = "_Layout";
}

Das Layout kann mit seinem vollständigen Pfad (Beispiel: /Pages/Shared/_Layout.cshtml oder /Views/Shared/_Layout.cshtml) oder über einen Teil seines Namens angegeben werden (Beispiel: _Layout). Wird ein Teil des Namens angegeben, dann sucht die Razor-Ansichts-Engine die Layoutdatei unter Verwendung des standardmäßigen Ermittlungsprozesses. Der Ordner, in dem sich die die Handlermethode (oder der Controller) befindet, wird zuerst durchsucht und danach der Ordner Shared. Dieser Ermittlungsprozess ist identisch mit dem Prozess zum Auffinden von Teilansichten.

Standardmäßig muss jedes Layout RenderBody aufrufen. Wo immer der Aufruf von RenderBody platziert ist, wird der Inhalt der Ansicht gerendert.

Abschnitte

Optional kann ein Layout auf mindestens einen Abschnitt verweisen, indem es RenderSection aufruft. Abschnitte geben an, wo bestimmte Seitenelemente platziert werden sollen. Jeder Aufruf von RenderSection kann angeben, ob dieser Abschnitt erforderlich ist:

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

@RenderSection("Scripts", required: false)

Wenn ein erforderlicher Bereich nicht gefunden werden kann, wird eine Ausnahme ausgelöst. Einzelne Ansichten verwenden die @section-Razor-Syntax , um den in einem Abschnitt zu rendernden Inhalt anzugeben. Wenn eine Seite oder eine Ansicht einen Abschnitt definiert, muss dieser auch gerendert werden. Andernfalls tritt ein Fehler auf.

Eine Beispieldefinition von @section in einer Razor Pages-Ansicht:

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

Im vorangehenden Code wird scripts/main.js dem Abschnitt scripts auf einer Seite oder in einer Ansicht hinzugefügt. Andere Seiten oder Ansichten in der gleichen App benötigen dieses Skript möglicherweise nicht und definieren einen Abschnitt zu Skripts.

In der folgenden Markupdatei wird die Datei _ValidationScriptsPartial.cshtml mit dem Partial-Taghilfsprogramm gerendert:

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

Die vorhergehende Markupdatei wurde durch Gerüst-Identity generiert.

Die Abschnitte, die auf einer Seite oder in einer Ansicht definiert wurden, stehen nur auf deren Layoutseite zur Verfügung. Teilansichten, Ansichtskomponenten und andere Teile eines Ansichtssystems können nicht auf sie verweisen.

Ignorieren von Abschnitten

Standardmäßig müssen der Text und die Abschnitte einer Inhaltsseite alle von der Layoutseite gerendert werden. Die Razor-Ansichts-Engine erzwingt dies, indem sie erfasst, ob der Text und jeder Abschnitt gerendert wurde.

Rufen Sie die Methoden IgnoreBody und IgnoreSection auf, um die Ansichtsengine anzuweisen, den Text oder die Abschnitte zu ignorieren.

Der Text und jeder Abschnitt einer Razor Page müssen entweder gerendert oder ignoriert werden.

Importieren gemeinsam verwendeter Anweisungen

Seiten und Ansichten können Razor-Anweisungen zum Importieren von Namespaces und Abhängigkeitsinjektion verwenden. Anweisungen, die von mehreren Ansichten gemeinsam verwendet werden, können in einer gemeinsam verwendeten _ViewImports.cshtml-Datei angegeben werden. Die _ViewImports-Datei unterstützt die folgenden Anweisungen:

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

Die Datei unterstützt keine anderen Razor-Features wie Funktionen und Abschnittsdefinitionen.

Eine _ViewImports.cshtml-Beispieldatei:

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

Die Datei _ViewImports.cshtml für eine ASP.NET Core MVC-App befindet sich normalerweise im Ordner Pages (oder Views). Eine Datei _ViewImports.cshtml kann auch in einen anderen Ordner verschoben werden. In diesem Fall wird sie nur auf Seiten oder Ansichten in diesem Ordner und in dessen Unterordnern angewendet. _ViewImports-Dateien werden beginnend ab der Stammebene verarbeitet und dann einzeln für jeden Ordner bis zum Speicherort der Seite oder der Ansicht selbst. Die _ViewImports-Einstellungen auf der Stammebene werden möglicherweise auf Ordnerebene außer Kraft gesetzt.

Nehmen Sie beispielsweise Folgendes an:

  • Die Datei _ViewImports.cshtml auf Stammebene umfasst @model MyModel1 and @addTagHelper *, MyTagHelper1.
  • Eine Unterordnerdatei _ViewImports.cshtml enthält @model MyModel2 und @addTagHelper *, MyTagHelper2.

Seiten und Ansichten im Unterordner haben Zugriff auf beide Taghilfsprogramme und das Modell MyModel2.

Wenn sich mehrere Dateien _ViewImports.cshtml in der Hierarchie befinden, umfasst das kombinierte Verhalten der Anweisungen Folgendes:

  • @addTagHelper, @removeTagHelper: werden nach der Reihe ausgeführt
  • @tagHelperPrefix: dasjenige, das der Ansicht am Nächsten ist, setzt die anderen außer Kraft
  • @model: dasjenige, das der Ansicht am Nächsten ist, setzt die anderen außer Kraft
  • @inherits: dasjenige, das der Ansicht am Nächsten ist, setzt die anderen außer Kraft
  • @using: alle einbezogen; Duplikate werden ignoriert
  • @inject: dasjenige, das der Ansicht am Nächsten ist, setzt für jede Eigenschaft alle anderen mit dem gleichen Namen außer Kraft

Ausführen von Code vor jeder Ansicht

Code, der ausgeführt werden muss, bevor die einzelnen Ansichten oder Seiten in die Datei _ViewStart.cshtml platziert werden. Gemäß der Konvention befindet sich die Datei _ViewStart.cshtml im Ordner Pages (oder View). Die in _ViewStart.cshtml aufgelisteten Anweisungen werden vor jeder vollständigen Ansicht (also keine Layouts und keine Teilansichten) ausgeführt. _ViewStart.cshtml ist genauso wie ViewImports.cshtml hierarchisch. Wenn eine Datei namens _ViewStart.cshtml im Ordner „View“ oder „Pages“ definiert wird, der mit einem Controller verknüpft ist, wird sie nach der Datei ausgeführt, die im Stamm des Ordners Pages (oder Views) definiert wurde (falls vorhanden).

Eine _ViewStart.cshtml-Beispieldatei:

@{
    Layout = "_Layout";
}

Die oben stehende Datei gibt an, dass alle Ansichten das _Layout.cshtml-Layout verwenden.

_ViewStart.cshtml und _ViewImports.cshtml werden in der Regel nicht im Ordner /Pages/Shared (oder /Views/Shared) platziert. Die Versionen dieser Dateien auf Anwendungsebene sollten direkt in den Ordner /Pages (oder /Views) platziert werden.