ASP.NET Core 中的配置Layout in ASP.NET Core

作者:Steve SmithDave BrockBy 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 Pages 和包含檢視的控制器。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 位於 Pages 資料夾。Razor Pages are in the Pages folder.
  • 包含檢視的控制器,使用 Views 資料夾進行檢視。Controllers with views uses a Views folder for views.

何謂配置What is a Layout

大部分的 Web 應用程式都會有通用配置,可提供使用者一致的巡覽頁面體驗。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. 所有這些共用項目可能都定義在 layout 檔案中,而之後應用程式內使用的任何檢視都可以參考該檔案。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.cshtmlBy 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: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.

根據預設,每個配置都必須呼叫 RenderBodyBy default, every layout must call RenderBody. 不論在何處呼叫 RenderBody,都會轉譯檢視內容。Wherever the call to RenderBody is placed, the contents of the view will be rendered.

章節Sections

配置可以選擇性地呼叫 ,以參考一或多個「區段」 RenderSectionA 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).

Razor Pages 檢視中的範例 @section 定義: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.cshtmlThe following markup uses the Partial Tag Helper to render _ValidationScriptsPartial.cshtml:

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

前述標記由 Scaffolding 識別 產生。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.

若要指示檢視引擎略過本文或區段,請呼叫 IgnoreBodyIgnoreSection 方法。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 importing 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

ASP.NET Core MVC 應用程式的 _ViewImports.cshtml 檔案通常會放在 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 *, MyTagHelper1The root level _ViewImports.cshtml file includes @model MyModel1 and @addTagHelper *, MyTagHelper1.
  • 子資料夾 _ViewImports.cshtml 檔案包含 @model MyModel2@addTagHelper *, MyTagHelper2A 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 檔案會位於頁面 (或檢視) 資料夾中。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.