Макет в ASP.NET CoreLayout in ASP.NET Core

Авторы: Стив Смит (Steve Smith) и Дейв Брок (Dave Brock)By Steve Smith and Dave Brock

На страницах и в представлениях часто есть общие визуальные и программные элементы.Pages and views frequently share visual and programmatic elements. В этой статье демонстрируются следующие возможности.This article demonstrates how to:

  • Использование общих макетов.Use common layouts.
  • Совместное использование директив.Share directives.
  • Запуск общего кода до отрисовки страниц или представлений.Run common code before rendering pages or views.

В этом документе рассматриваются два разных подхода к ASP.NET Core MVC: Razor страницы и контроллеры с представлениями.This document discusses layouts for the two different approaches to ASP.NET Core MVC: Razor Pages and controllers with views. С этой точки зрения различия минимальны:For this topic, the differences are minimal:

  • Razor Страницы находятся в папке pages .Razor Pages are in the Pages folder.
  • Контроллеры с представлениями используют папку Views для представлений.Controllers with views uses a Views folder for views.

Что такое макетWhat is a Layout

Большинство веб-приложений имеют общий макет, который обеспечивает согласованный пользовательский интерфейс при переходе между страницами.Most web apps have a common layout that provides the user with a consistent experience as they navigate from page to page. Макет, как правило, включает в себя общие элементы пользовательского интерфейса, такие как верхний и нижний колонтитулы, а также элементы навигации или меню.The layout typically includes common user interface elements such as the app header, navigation or menu elements, and footer.

Пример макета страницы

Структуры HTML, такие как скрипты и таблицы стилей, также часто используются совместно несколькими страницами в приложении.Common HTML structures such as scripts and stylesheets are also frequently used by many pages within an 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. Макеты позволяют сократить дублирование кода в представлениях.Layouts reduce duplicate code in views.

В соответствии с соглашением макет по умолчанию для приложения ASP.NET Core имеет имя _Layout.cshtml.By convention, the default layout for an ASP.NET Core app is named _Layout.cshtml. В новых проектах ASP.NET Core, созданных с применением шаблонов, используются следующие файлы макета.The layout files for new ASP.NET Core projects created with the templates are:

  • Razor Страницы: pages/Shared/_layout. cshtmlRazor Pages: Pages/Shared/_Layout.cshtml

    Папка Pages в обозревателе решений

  • Контроллер с представлениями: папка Views/Shared/_Layout.cshtmlController with views: Views/Shared/_Layout.cshtml

    Папка Views в обозревателе решений

Макет определяет шаблон верхнего уровня для представлений в приложении.The layout defines a top level template for views in the app. Для приложений макет не требуется.Apps don't require a layout. В приложении может быть определено несколько макетов для разных представлений.Apps can define more than one layout, with different views specifying different layouts.

В следующем коде показан файл макета для проекта, созданного по шаблону, с контроллером и представлениями: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>

Указание макетаSpecifying a Layout

Razor представления имеют Layout свойство.Razor views have a Layout property. С его помощью указывается макет в отдельных представлениях:Individual views specify a layout by setting this property:

@{
    Layout = "_Layout";
}

Указанный макет может использовать полный путь (например, /Pages/Shared/_Layout.cshtml или /Views/Shared/_Layout.cshtml) или частичное имя (например, _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). Если указано частичное имя, Razor обработчик представлений выполняет поиск файла макета с помощью стандартного процесса обнаружения.When a partial name is provided, the Razor view engine searches for the layout file using its standard discovery process. Сначала поиск выполняется в папке, где существует метод обработчика (или контроллер), а затем в папке Shared.The folder where the handler method (or controller) exists is searched first, followed by the Shared folder. Процесс обнаружения аналогичен тому, который применяется для поиска частичных представлений.This discovery process is identical to the process used to discover partial views.

По умолчанию каждый макет должен вызывать метод RenderBody.By default, every layout must call RenderBody. При каждом вызове RenderBody содержимое представления будет преобразовываться для просмотра.Wherever the call to RenderBody is placed, the contents of the view will be rendered.

РазделыSections

Макет может при необходимости ссылаться на один или несколько разделов, вызывая метод RenderSection.A layout can optionally reference one or more sections, by calling RenderSection. Разделы — это средство для упорядочения размещения определенных элементов на странице.Sections provide a way to organize where certain page elements should be placed. В каждом вызове RenderSection можно указывать, является ли раздел обязательным или необязательным: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)

Если обязательный раздел не найден, создается исключение.If a required section isn't found, an exception is thrown. Отдельные представления задают содержимое, которое должно быть отображено в разделе с использованием @section Razor синтаксиса.Individual views specify the content to be rendered within a section using the @section Razor syntax. Если на странице или в представлении определяется раздел, он должен быть преобразован для просмотра (в противном случае произойдет ошибка).If a page or view defines a section, it must be rendered (or an error will occur).

Пример @section определения в Razor представлении страниц:An example @section definition in Razor Pages view:

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

В приведенном выше коде scripts/main.js добавляется в раздел scripts на странице или в представлении.In the preceding code, scripts/main.js is added to the scripts section on a page or view. Другие страницы или представления в одном приложении могут не требовать этот скрипт и не определять раздел скриптов.Other pages or views in the same app might not require this script and wouldn't define a scripts section.

Следующая разметка использует вспомогательную функция тега частичного представления для подготовки к просмотру _ValidationScriptsPartial.cshtml:The following markup uses the Partial Tag Helper to render _ValidationScriptsPartial.cshtml:

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

Предыдущая разметка была сформирована формированием шаблонов Identity .The preceding markup was generated by scaffolding Identity.

Разделы, определенные на странице или в представлении, доступны только непосредственно на странице макета.Sections defined in a page or view are available only in its immediate layout page. На них нельзя ссылаться из частичных представлений, компонентов представлений или других частей системы представлений.They cannot be referenced from partials, view components, or other parts of the view system.

Пропуск разделовIgnoring sections

По умолчанию тело и все разделы страницы содержимого должны преобразовываться для просмотра страницей макета.By default, the body and all sections in a content page must all be rendered by the layout page. RazorОбработчик представлений применяет это, отслеживая отображение текста и каждого раздела.The Razor view engine enforces this by tracking whether the body and each section have been rendered.

Чтобы подсистема представлений пропустила тело или разделы, вызовите методы IgnoreBody и IgnoreSection.To instruct the view engine to ignore the body or sections, call the IgnoreBody and IgnoreSection methods.

Текст и все разделы Razor страницы должны быть либо визуализированы, либо игнорироваться.The body and every section in a Razor page must be either rendered or ignored.

Импорт общих директивImporting Shared Directives

Представления и страницы могут использовать Razor директивы для импорта пространств имен и использования внедрения зависимостей.Views and pages can use Razor directives to import namespaces and use dependency injection. Директивы, используемые несколькими представлениями, можно указать в общем файле _ViewImports.cshtml.Directives shared by many views may be specified in a common _ViewImports.cshtml file. Файл _ViewImports поддерживает следующие директивы:The _ViewImports file supports the following directives:

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

Файл не поддерживает другие Razor функции, такие как функции и определения разделов.The file doesn't support other Razor features, such as functions and section definitions.

Пример файла _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

Файл _ViewImports.cshtml для приложения ASP.NET Core MVC обычно находится в папке Pages (или Views).The _ViewImports.cshtml file for an ASP.NET Core MVC app is typically placed in the Pages (or Views) folder. Файл _ViewImports.cshtml можно поместить в любую папку, но в этом случае он будет применяться только к страницам или представлениям в этой папке и вложенных в нее папках.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. Файлы _ViewImports обрабатываются начиная с корневого уровня, а затем для каждой папки вплоть до расположения самой страницы или представления._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. Параметры _ViewImports, заданные на корневом уровне, можно переопределить на уровне папки._ViewImports settings specified at the root level may be overridden at the folder level.

Например, предположим, что:For example, suppose:

  • Файл корневого уровня _ViewImports.cshtml включает @model MyModel1 и @addTagHelper *, MyTagHelper1.The root level _ViewImports.cshtml file includes @model MyModel1 and @addTagHelper *, MyTagHelper1.
  • Файл вложенной папки _ViewImports.cshtml включает @model MyModel2 и @addTagHelper *, MyTagHelper2.A subfolder _ViewImports.cshtml file includes @model MyModel2 and @addTagHelper *, MyTagHelper2.

Страницы и представления во вложенной папке будут иметь доступ к вспомогательным функциям тегов и модели MyModel2.Pages and views in the subfolder will have access to both Tag Helpers and the MyModel2 model.

Если в иерархии файлов найдено несколько файлов _ViewImports.cshtml, директивы ведут себя следующим образом:If multiple _ViewImports.cshtml files are found in the file hierarchy, the combined behavior of the directives are:

  • @addTagHelper, @removeTagHelper: выполняются все директивы по порядку;@addTagHelper, @removeTagHelper: all run, in order
  • @tagHelperPrefix: ближайшая к представлению директива переопределяет все остальные;@tagHelperPrefix: the closest one to the view overrides any others
  • @model: ближайшая к представлению директива переопределяет все остальные;@model: the closest one to the view overrides any others
  • @inherits: ближайшая к представлению директива переопределяет все остальные;@inherits: the closest one to the view overrides any others
  • @using: включаются все директивы, повторяющиеся пропускаются;@using: all are included; duplicates are ignored
  • @inject: для каждого свойства ближайшая к представлению директива переопределяет все остальные директивы с тем же именем свойства.@inject: for each property, the closest one to the view overrides any others with the same property name

Выполнение кода перед каждым представлениемRunning Code Before Each View

Код, который должен быть запущен перед каждым представлением или страницей, нужно поместить в файл _ViewStart.cshtml.Code that needs to run before each view or page should be placed in the _ViewStart.cshtml file. По соглашению файл _ViewStart.cshtml находится в папке Pages (или Views).By convention, the _ViewStart.cshtml file is located in the Pages (or Views) folder. Операторы, перечисленные в файле _ViewStart.cshtml, выполняются перед каждым полным представлением (но не перед макетами и не перед частичными представлениями).The statements listed in _ViewStart.cshtml are run before every full view (not layouts, and not partial views). Так же как файлы ViewImports.cshtml, файлы _ViewStart.cshtml являются иерархическими.Like ViewImports.cshtml, _ViewStart.cshtml is hierarchical. Если файл _ViewStart.cshtml определен в папке представлений или страниц, он будет применяться после определенного в корне папки Pages (или Views) (при его наличии).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).

Пример файла _ViewStart.cshtml:A sample _ViewStart.cshtml file:

@{
    Layout = "_Layout";
}

Приведенный файл предписывает всем представлениям использовать макет _Layout.cshtml.The file above specifies that all views will use the _Layout.cshtml layout.

_ViewStart.cshtml и _ViewImports.cshtml обычно не помещаются в папку /Pages/Shared (или /Views/Shared)._ViewStart.cshtml and _ViewImports.cshtml are not typically placed in the /Pages/Shared (or /Views/Shared) folder. Версии этих файлов, которые должны действовать на уровне приложения, следует помещать непосредственно в папку /Pages (или /Views).The app-level versions of these files should be placed directly in the /Pages (or /Views) folder.