ASP.NET Core でのレイアウト

作成者: Steve SmithDave Brock

ページやビューは、多くの場合、ビジュアルおよびプログラムの要素を共有します。 この記事では、次の方法を示します。

  • 共通のレイアウトを使用する。
  • ディレクティブを共有する。
  • ページまたはビューを表示する前に、共通のコードを実行する。

このドキュメントでは、ASP.NET Core MVC に対するアプローチとして、Razor Pages とビューを含むコントローラーの 2 種類のレイアウトについて説明します。 このトピックでは、違いは最小限です。

  • Razor Pages は、Pages フォルダーにあります。
  • ビューを含むコントローラーでは、Views フォルダーをビューに使用します。

レイアウトとは

ほとんどの Web アプリには、ユーザーがページ間を移動する際に一貫性のあるエクスペリエンスを提供する共通レイアウトがあります。 通常、このレイアウトには、アプリのヘッダー、ナビゲーションまたはメニュー要素、フッターなどの共通のユーザー インターフェイス要素が含まれます。

Page Layout example

スクリプトやスタイルシートなどの共通の HTML 構造も、アプリ内の多くのページで頻繁に使用されます。 これらの共有要素をすべて layout ファイルで定義することで、アプリ内で使用する任意のビューで参照できるようになります。 レイアウトにより、ビュー内の重複するコードを削減できます。

規則により、ASP.NET Core アプリの既定のレイアウトには _Layout.cshtml という名前が付けられます。 テンプレートを使用すると、次のような新しい ASP.NET Core プロジェクトのレイアウト ファイルが作成されます。

  • Razor ページ: Pages/Shared/_Layout.cshtml

    Pages folder in Solution Explorer

  • ビューを持つコントローラー: Views/Shared/_Layout.cshtml

    Views folder in Solution Explorer

レイアウトでは、アプリのビューの最上位のテンプレートが定義されています。 アプリにはレイアウトは必要ありません。 アプリでは、異なるレイアウトを指定するさまざまなビューで、複数のレイアウトを定義できます。

次のコードでは、コントローラーとビューを含むテンプレートで作成されたプロジェクトのレイアウト ファイルを示します。

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

レイアウトの指定

Razor ビューには Layout プロパティがあります。 個々のビューは、このプロパティを設定することでレイアウトを指定します。

@{
    Layout = "_Layout";
}

指定したレイアウトでは、完全なパス (たとえば、 /Pages/Shared/_Layout.cshtml または) または /Views/Shared/_Layout.cshtml部分名 (例: _Layout) を使用できます。 名前の部分を指定すると、Razor ビュー エンジンが標準の検出プロセスを使用して、レイアウト ファイルを検索します。 ハンドラー メソッド (またはコントローラー) が存在するフォルダーが最初に検索され、その後で Shared フォルダーが検索されます。 この検出プロセスは、部分ビューの検出に使用されるのと同じプロセスです。

既定では、すべてのレイアウトで RenderBody を呼び出す必要があります。 RenderBody への呼び出しが配置されると、ビューのコンテンツがレンダリングされます。

セクション

レイアウトは、必要に応じて RenderSection を呼び出すことで、1 つ以上のセクションを参照することができます。 セクションは、特定のページ要素の配置場所を整理する方法を提供します。 RenderSection の呼び出しごとに、そのセクションを必須またはオプションにするかどうかを指定できます。

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

@RenderSection("Scripts", required: false)

必須のセクションが見つからない場合、例外がスローされます。 個々のビューでは、構文を使用してセクション内でレンダリングされるコンテンツを @sectionRazor 指定します。 ページまたはビューでセクションを定義する場合は、レンダリングされる必要があります (そうしないと、エラーが発生します)。

Razor Pages ビューでの @section 定義の例:

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

上記のコードでは、 scripts/main.js ページまたはビューの scripts セクションに追加されます。 同じアプリの他のページまたはビューではこのスクリプトは必要なく、スクリプト セクションは定義されていません。

次のマークアップでは、 部分タグ ヘルパー を使用してレンダリング _ValidationScriptsPartial.cshtmlします。

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

上記のマークアップは、スキャフォールディング Identity で生成されました。

ページまたはビューで定義されたセクションは、そのイミディエイト レイアウト ページでのみ使用できます。 これらは、部分、ビュー コンポーネント、またはビュー システムの他の部分からは参照できません。

セクションの無視

既定では、コンテンツ ページの本文とすべてのセクションがレイアウト ページですべてレンダリングされる必要があります。 Razor ビュー エンジンは、本文と各セクションがレンダリングされているかどうかを追跡することによってこれを実行します。

本文またはセクションを無視するようにビュー エンジンに指示するには、IgnoreBody メソッドと IgnoreSection メソッドを呼び出します。

Razor ページ内の本文とすべてのセクションは、レンダリングされるか無視される必要があります。

共有ディレクティブのインポート

ビューやページでは、Razor ディレクティブを使用して名前空間をインポートして依存関係の挿入を使用できます。 多くのビューで共有されるディレクティブは、共通の _ViewImports.cshtml ファイルで指定できます。 _ViewImports ファイルは、次のディレクティブをサポートします。

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

このファイルは、関数やセクションの定義などの Razor のその他の機能はサポートしていません。

_ViewImports.cshtml ファイルのサンプル:

@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) フォルダーに配置されます。 ファイルは任意の _ViewImports.cshtml フォルダー内に配置できます。その場合、そのフォルダーとそのサブフォルダー内のページまたはビューにのみ適用されます。 _ViewImports ファイルの処理はルート レベルで開始されてから、フォルダーごとに、ページまたはビュー自体の場所に至るまで行われます。 ルート レベルで指定された _ViewImports の設定は、フォルダー レベルでオーバーライドされる可能性があります。

たとえば、次のように想定します。

  • ルート レベル _ViewImports.cshtml ファイルには、次のものが@addTagHelper *, MyTagHelper1含まれます@model MyModel1
  • サブフォルダー _ViewImports.cshtml ファイルのインクルード @model MyModel2@addTagHelper *, MyTagHelper2.

サブフォルダー内のページおよびビューは、タグ ヘルパーと MyModel2 モデルの両方にアクセスできます。

ファイル階層内に複数 _ViewImports.cshtml のファイルが見つかった場合、ディレクティブの組み合わせ動作は次のようになります。

  • @addTagHelper@removeTagHelper: 順番どおりにすべて実行
  • @tagHelperPrefix: ビューに最も近いものが、他のものをすべてをオーバーライドする
  • @model: ビューに最も近いものが、他のものをすべてをオーバーライドする
  • @inherits: ビューに最も近いものが、他のものをすべてをオーバーライドする
  • @using: すべてが含まれ、重複は無視される
  • @inject: プロパティごとに、ビューに最も近いものが、同じプロパティ名を持つ他のものすべてをオーバーライドする

各ビューの前にコードを実行する

各ビューまたはページをファイルに配置 _ViewStart.cshtml する前に実行する必要があるコード。 規則により、 _ViewStart.cshtml ファイルは Pages (または Views) フォルダーにあります。 _ViewStart.cshtml に一覧表示されているステートメントは、すべての (レイアウトでもなく、部分ビューでもない) 完全なビューより前に実行されます。 ViewImports.cshtml と同様に、_ViewStart.cshtml階層型です。 _ViewStart.cshtmlファイルがビューまたはページ フォルダーで定義されている場合は、Pages (または Views) フォルダー (存在する場合) のルートで定義されたファイルの後に実行されます。

_ViewStart.cshtml ファイルのサンプル:

@{
    Layout = "_Layout";
}

上記のファイルは、すべてのビューで _Layout.cshtml レイアウトを使用することを指定します。

_ViewStart.cshtml通常_ViewImports.cshtml/Pages/Shared (または /Views/Shared) フォルダーには配置されません。 これらのファイルのアプリ レベルのバージョンは、/Pages (または /Views) フォルダーに直接配置する必要があります。