ASP.NET Core でのレイアウト

作成者: Steve SmithDave Brock

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

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

このドキュメントでは、Core MVC を使用するための 2 つの異なる方法の ASP.NET ページとビューを含むコントローラーについて Razor 説明します。 このトピックでは、違いは最小限です。

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

レイアウトとは

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

ページ レイアウトの例

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

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

  • Razor Pages: Pages/Shared/_Layout.cshtml

    ソリューション エクスプローラーの Pages フォルダー

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

    ソリューション エクスプローラーの 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>

レイアウトの指定

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)

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

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

@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

このファイルでは、関数やセクション 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 ファイルには、@model MyModel1@addTagHelper *, MyTagHelper1 が含まれます。
  • サブフォルダーの _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) フォルダーに直接配置する必要があります。