次の方法で共有


ASP.NET Web ページ (Razor) サイトでの一貫性のあるレイアウトの作成

作成者: Tom FitzMacken

この記事では、ASP.NET Web ページ (Razor) Web サイトでレイアウト ページを使用して、再利用可能なコンテンツ ブロック (ヘッダーやフッターなど) を作成し、サイト内のすべてのページで一貫した外観を作成する方法について説明します。

学習内容:

  • ヘッダーやフッターなどの再利用可能なコンテンツ ブロックを作成する方法。
  • レイアウトを使用してサイト内のすべてのページを一貫した外観で作成する方法。
  • 実行時にレイアウト ページにデータを渡す方法。

この記事で紹介する ASP.NET 機能は次のとおりです。

  • コンテンツ ブロックは、複数のページに挿入される HTML 形式のコンテンツを含むファイルです。
  • レイアウト ページは、Web サイト上のページで共有できる HTML 形式のコンテンツを含むページです。
  • RenderPageRenderBodyRenderSection メソッドは、ページ要素を挿入する ASP.NET を示します。
  • コンテンツ ブロックとレイアウト ページの間でデータを共有できる PageData ディクショナリ。

チュートリアルで使用するソフトウェアのバージョン

  • ASP.NET Web ページ (Razor) 3

このチュートリアルは、ASP.NET Web ページ 2 にも適用できます。

レイアウト ページについて

多くの Web サイトには、ヘッダーやフッターなどのすべてのページに表示されるコンテンツや、ログインしていることをユーザーに通知するボックスがあります。 ASP.NET では、通常の Web ページと同様に、テキスト、マークアップ、コードを含むことができるコンテンツ ブロックを含む個別のファイルを作成できます。 その後、情報を表示するサイトの他のページにコンテンツ ブロックを挿入できます。 そうすることで、すべてのページに同じコンテンツをコピーして貼り付ける必要はありません。 このような一般的なコンテンツを作成すると、サイトの更新も容易になります。 コンテンツを変更する必要がある場合は、1 つのファイルを更新するだけで、コンテンツが挿入されたすべての場所に変更が反映されます。

次の図は、コンテンツ ブロックのしくみを示しています。 ブラウザーが Web サーバーからページを要求すると、ASP.NET は、メイン ページで RenderPage メソッドが呼び出された時点でコンテンツ ブロックを挿入します。 完了した (マージされた) ページがブラウザーに送信されます。

Conceptual diagram showing how the RenderPage method inserts a referenced page into the current page.

この手順では、別のファイルにある 2 つのコンテンツ ブロック (ヘッダーとフッター) を参照するページを作成します。 サイト内の任意のページで、これらの同じコンテンツ ブロックを使用できます。 完了すると、次のようなページが表示されます。

Screenshot showing a page in the browser that results from running a page that includes calls to the RenderPage method.

  1. Web サイトのルート フォルダーに Index.cshtml という名前のファイルを作成します。

  2. 既存のマークアップを次に置き換えます。

    <!DOCTYPE html>
    <html>
      <head>
        <title>Main Page</title>
      </head>
      <body>
    
        <h1>Index Page Content</h1>
        <p>This is the content of the main page.</p>
    
      </body>
    </html>
    
  3. ルート フォルダーに Shared という名前のフォルダーを作成します。

    Note

    Web ページ間で共有されているファイルは、Shared という名前のフォルダーに格納するのが一般的です。

  4. Shared フォルダーに、_Header.cshtml という名前のファイルを作成します。

  5. 既存のコンテンツを次に置き換えます。

    <div class="header">This is header text.</div>
    

    ファイル名は _Header.cshtml で、プレフィックスとしてアンダースコア (_) が付いていることに注意してください。 名前がアンダースコアで始まる場合、ASP.NET はブラウザーにページを送信しません。 これにより、ユーザーがこれらのページを直接 (誤ってまたはそれ以外の方法で) 要求するのを防ぐことができます。 ユーザーがこれらのページを要求できないようにするため、アンダースコアを使用してコンテンツ ブロックが含まれるページに名前を付けることをお勧めします。これらのページは、他のページに厳密に挿入する必要があります。

  6. Shared フォルダーで、_Footer.cshtml という名前のファイルを作成し、内容を次のように置き換えます。

    <div class="footer">&copy; 2012 Contoso Pharmaceuticals. All rights reserved.
    </div>
    
  7. Index.cshtml ページで、次に示すように、RenderPage メソッドに 2 つの呼び出しを追加します。

    <!DOCTYPE html>
    <html>
      <head>
        <title>Main Page</title>
      </head>
      <body>
    
        @RenderPage("~/Shared/_Header.cshtml")
    
        <h1>Index Page Content</h1>
        <p>This is the content of the main page.</p>
    
        @RenderPage("~/Shared/_Footer.cshtml")
    
      </body>
    </html>
    

    これは、Web ページにコンテンツ ブロックを挿入する方法を示しています。 RenderPage メソッドを呼び出し、その時点で挿入する内容を持つファイルの名前を渡します。 ここでは、_Header.cshtml ファイルと _Footer.cshtml ファイルの内容を Index.cshtml ファイルに挿入します。

  8. ブラウザーで Index.cshtml ページを実行します。 (WebMatrix では、[ファイル] ワークスペースでファイルを右クリックし、[ブラウザーで起動] を選択します)。

  9. ブラウザーで、ページのソースを表示します。 (たとえば、Internet Explorer でページを右クリックし、[ソースの表示] をクリックします)。

    これにより、ブラウザーに送信された Web ページ マークアップを表示できます。これにより、インデックス ページのマークアップとコンテンツ ブロックが結合されます。 次の例は、Index.cshtml 用にレンダリングされるページ ソースを示しています。 Index.cshtml に挿入した RenderPage への呼び出しは、ヘッダー ファイルとフッター ファイルの実際の内容に置き換えられました。

    <!DOCTYPE html>
    <html>
      <head>
        <title>Main Page</title>
      </head>
      <body>
    
      <div class="header">
        This is header text.
      </div>
    
        <h1>Index Page Content</h1>
        <p>This is the content of the main page.</p>
    
      <div class="footer">
        &copy; 2012 Contoso Pharmaceuticals. All rights reserved.
      </div>
    
      </body>
    </html>
    

レイアウト ページを使用して一貫性のある外観を作成する

ここまで、複数のページに同じコンテンツを簡単に含められることを見てきました。 サイトの一貫性のある外観を作成するためのより構造化されたアプローチは、レイアウト ページを使用することです。 レイアウト ページは Web ページの構造を定義しますが、実際のコンテンツは含まれません。 レイアウト ページを作成したら、コンテンツを含む Web ページを作成し、それらをレイアウト ページにリンクできます。 これらのページが表示されると、レイアウト ページに従って書式が設定されます。 (この意味で、レイアウト ページは、他のページで定義されているコンテンツのテンプレートの一種として機能します。)

レイアウト ページは、RenderBody メソッドの呼び出しが含まれている点を除き、HTML ページと同じです。 レイアウト ページ内の RenderBody メソッドの位置によって、コンテンツ ページの情報が含まれる場所が決まります。

次の図は、コンテンツ ページとレイアウト ページが実行時に統合される方法と、最終的な Web ページが生成される方法を示しています。 ブラウザーではコンテンツ ページが要求されます。 コンテンツ ページには、ページの構造に使用するレイアウト ページを指定するコードがあります。 レイアウト ページでは、RenderBody メソッドが呼び出された時点でコンテンツが挿入されます。 前のセクションで行った方法で RenderPage メソッドを呼び出すことで、コンテンツ ブロックをレイアウト ページに挿入することもできます。 Web ページが完了すると、ブラウザーに送信されます。

Screenshot showing a page in the browser that results from running a page that includes calls to the RenderBody method.

次の手順では、レイアウト ページを作成し、それにコンテンツ ページをリンクする方法を示します。

  1. Web サイトの Shared フォルダーに、_Layout1.cshtml という名前のファイルを作成します。

  2. 既存のコンテンツを次に置き換えます。

    <!DOCTYPE html>
    <html>
      <head>
        <title>Structured Content </title>
        <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
      </head>
      <body>
        @RenderPage("~/Shared/_Header2.cshtml")
        <div id="main">
          @RenderBody()
        </div>
        <div id="footer">
          &copy; 2012 Contoso Pharmaceuticals. All rights reserved.
        </div>
      </body>
    </html>
    

    レイアウト ページで RenderPage メソッドを使用して、コンテンツ ブロックを挿入します。 レイアウト ページには、RenderBody メソッドの呼び出しを 1 つだけ含めることができます。

  3. Shared フォルダーで、_Header2.cshtml という名前のファイルを作成し、既存の内容を次のように置き換えます。

    <div id="header">Creating a Consistent Look</div>
    
  4. ルート フォルダーで、新しいフォルダーを作成し、Styles という名前を付けます。

  5. Styles フォルダーで、Site.css という名前のファイルを作成し、次のスタイル定義を追加します。

    h1 {
        border-bottom: 3px solid #cc9900;
        font: 2.75em/1.75em Georgia, serif;
        color: #996600;
    }
    
    ul {
        list-style-type: none;
    }
    
    body {
        margin: 0;
        padding: 1em;
        background-color: #ffffff;
        font: 75%/1.75em "Trebuchet MS", Verdana, sans-serif;
        color: #006600;
    }
    
    #list {
        margin: 1em 0 7em -3em;
        padding: 1em 0 0 0;
        background-color: #ffffff;
        color: #996600;
        width: 25%;
        float: left;
    }
    
    #header, #footer {
        margin: 0;
        padding: 0;
        color: #996600;
    }
    

    これらのスタイル定義は、レイアウト ページでスタイル シートを使用する方法を示すためだけのものです。 必要に応じて、これらの要素に独自のスタイルを定義できます。

  6. ルート フォルダーで、Content1.cshtml という名前のファイルを作成し、既存の内容を次のように置き換えます。

    @{
        Layout = "~/Shared/_Layout1.cshtml";
    }
    
    <h1> Structured Content </h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.</p>
    

    これは、レイアウト ページを使用するページです。 ページの上部にあるコード ブロックは、このコンテンツの書式設定に使用するレイアウト ページを示します。

  7. ブラウザーで Content1.cshtml を実行します。 レンダリングされたページでは、_Layout1.cshtml で定義されている形式およびスタイル シートと、Content1.cshtml で定義されているテキスト (コンテンツ) が使用されます。

    [The screenshot shows running Content 1 dot CSHTML in a browser.]

    手順 6 を繰り返して、同じレイアウト ページを共有できる追加のコンテンツ ページを作成できます。

    Note

    フォルダー内のすべてのコンテンツ ページに対して同じレイアウト ページを自動的に使用できるように、サイトを設定できます。 詳細については、ASP.NET Web ページのサイト全体の動作のカスタマイズに関するページを参照してください。

複数のコンテンツ セクションを含むレイアウト ページの設計

コンテンツ ページには複数のセクションを含めることができます。これは、複数の領域を置き換え可能なコンテンツを含むレイアウトを使用する場合に便利です。 コンテンツ ページでは、各セクションに一意の名前を付けます。 (既定のセクションは名前なしのままです。)レイアウト ページでは、RenderBody メソッドを追加して、名前なし (既定) のセクションを表示する場所を指定します。 その後、名前付きセクションを個別にレンダリングするために、個別の RenderSection メソッドを追加します。

次の図は、複数のセクションに分割された ASP.NET コンテンツを処理する方法を示しています。 それぞれの名前付きセクションは、コンテンツ ページのセクション ブロックに含まれています。 (例は名前付きの Header および List です。)フレームワークは、RenderSection メソッドが呼び出された時点でレイアウト ページにコンテンツ セクションを挿入します。 前に説明したとおり、名前なし (既定) のセクションは、RenderBody メソッドが呼び出されるポイントに挿入されます。

Conceptual diagram showing how the RenderSection method inserts references sections into the current page.

この手順では、複数のコンテンツ セクションを含むコンテンツ ページを作成する方法と、複数のコンテンツ セクションをサポートするレイアウト ページを使用してレンダリングする方法を示します。

  1. Shared フォルダーに、_Layout2.cshtml という名前のファイルを作成します。

  2. 既存のコンテンツを次に置き換えます。

    <!DOCTYPE html>
    <html>
      <head>
        <title>Multisection Content</title>
        <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
      </head>
      <body>
        <div id="header">
          @RenderSection("header")
        </div>
        <div id="list">
          @RenderSection("list")
        </div>
        <div id="main">
          @RenderBody()
        </div>
        <div id="footer">
          &copy; 2012 Contoso Pharmaceuticals. All rights reserved.
        </div>
      </body>
    </html>
    

    RenderSection メソッドを使用して、ヘッダー セクションとリスト セクションの両方をレンダリングします。

  3. ルート フォルダーで、Content2.cshtml という名前のファイルを作成し、既存の内容を次のように置き換えます。

    @{
        Layout = "~/Shared/_Layout2.cshtml";
    }
    
    @section header {
        <div id="header">
            Creating a Consistent Look
        </div>
    }
    
    @section list {
        <ul>
            <li>Lorem</li>
            <li>Ipsum</li>
            <li>Dolor</li>
            <li>Consecte</li>
            <li>Eiusmod</li>
            <li>Tempor</li>
            <li>Incididu</li>
        </ul>
    }
    
    <h1>Multisection Content</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.</p>
    

    このコンテンツ ページには、ページの上部にコード ブロックが含まれています。 それぞれの名前付きセクションは、セクション ブロックに含まれています。 ページの残りの部分には、既定 (名前なし) のコンテンツ セクションが含まれています。

  4. ブラウザーで Content2.cshtml を実行します。

    Screenshot showing a page in the browser that results from running a page that includes calls to the RenderSection method.

コンテンツ セクションを省略可能にする

通常、コンテンツ ページで作成するセクションは、レイアウト ページで定義されているセクションと一致する必要があります。 次のような場合に、エラーが発生する可能性があります。

  • コンテンツ ページには、レイアウト ページに対応するセクションがないセクションが含まれています。
  • レイアウト ページには、コンテンツがないセクションが含まれています。
  • レイアウト ページには、同じセクションを複数回レンダリングしようとするメソッド呼び出しが含まれます。

ただし、レイアウト ページでセクションが省略可能であると宣言することで、名前付きセクションのこの動作をオーバーライドできます。 これにより、レイアウト ページを共有できる複数のコンテンツ ページを定義できますが、特定のセクションのコンテンツが含まれる場合と含まれない場合があります。

  1. Content2.cshtml を開き、次のセクションを削除します。

    @section header {
      <div id="header">
        Creating a Consistent Look
      </div>
    }
    
  2. ページを保存し、ブラウザーで実行します。 レイアウト ページで定義されているセクション (ヘッダー セクション) のコンテンツがコンテンツ ページに表示されないため、エラー メッセージが表示されます。

    Screenshot that shows the error that occurs if you run a page that calls RenderSection method but the corresponding section is not provided.

  3. Shared フォルダーで、_Layout2.cshtml ページを開き、次の行を置き換えます。

    @RenderSection("header")
    

    を、以下のコードに置き換えます。

    @RenderSection("header", required: false)
    

    代替手段として、前のコード行を次のコード ブロックに置き換えて、同じ結果を生成することもできます。

    @if (IsSectionDefined("header")) {
        @RenderSection("header")
    }
    
  4. ブラウザーで Content2.cshtml ページをもう一度実行します。 (ブラウザーでこのページを開いたままにしている場合は、更新してください。)この時点では、ヘッダーがないにもかかわらず、エラーなしでページが表示されます。

レイアウト ページにデータを渡す

レイアウト ページで参照する必要があるデータがコンテンツ ページで定義されている場合があります。 その場合は、コンテンツ ページからレイアウト ページにデータを渡す必要があります。 たとえば、ユーザーのログイン状態を表示する場合や、ユーザー入力に基づいてコンテンツ領域を表示または非表示にする場合などです。

コンテンツ ページからレイアウト ページにデータを渡すには、コンテンツ ページの PageData プロパティに値を入れることができます。 PageData プロパティは、ページ間で渡すデータを保持する名前と値のペアのコレクションです。 レイアウト ページでは、PageData プロパティから値を読み取ることができます。

こちらに別の図を示します。 この図は、ASP.NET で PageData プロパティを使用して、コンテンツ ページからレイアウト ページに値を渡す方法を示しています。 ASP.NET が Web ページの構築を開始すると、PageData コレクションが作成されます。 コンテンツ ページでは、PageData コレクションにデータを入れるコードを記述します。 PageData コレクションの値には、コンテンツ ページ内の他のセクションまたは追加のコンテンツ ブロックからアクセスすることもできます。

Conceptual diagram that shows how a content page can populate a PageData dictionary and pass that information to the layout page.

次の手順は、コンテンツ ページからレイアウト ページにデータを渡す方法を示しています。 ページを実行すると、レイアウト ページで定義されているリストをユーザーが表示/非表示を切り替えられるボタンが表示されます。 ユーザーがボタンをクリックすると、PageData プロパティに true/false (Boolean) 値が設定されます。 レイアウト ページはその値を読み取り、false の場合はリストを非表示にします。 値はコンテンツ ページでも使用され、[リストの非表示] ボタンと [リストの表示] ボタンのどちらを表示するかを決定します。

[Screenshot shows the Passing Data page.]

  1. ルート フォルダーで、Content3.cshtml という名前のファイルを作成し、既存の内容を次のように置き換えます。

    @{
        Layout = "~/Shared/_Layout3.cshtml";
    
        PageData["Title"] = "Passing Data";
        PageData["ShowList"] = true;
    
        if (IsPost) {
            if (Request.Form["list"] == "off") {
                PageData["ShowList"] = false;
            }
        }
    }
    
    @section header {
      <div id="header">
        Creating a Consistent Look
      </div>
    }
    
    <h1>@PageData["Title"]</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.</p>
    
    @if (PageData["ShowList"] == true) {
        <form method="post" action="">
          <input type="hidden" name="list" value="off" />
          <input type="submit" value="Hide List" />
        </form>
    }
    else {
        <form method="post" action="">
          <input type="hidden" name="list" value="on" />
          <input type="submit" value="Show List" />
        </form>
    }
    

    コードでは、Web ページのタイトルと true または false の 2 つのデータを PageData プロパティに格納して、リストを表示するかどうかを指定します。

    ASP.NET では、コード ブロックを使用して条件付きで HTML マークアップをページに配置できることに注意してください。 たとえば、ページ本文の if/else ブロックは、PageData["ShowList"] が true に設定されているかどうかに応じて、表示するフォームを決定します。

  2. Shared フォルダーで、_Layout3.cshtml という名前のファイルを作成し、既存の内容を次のように置き換えます。

    <!DOCTYPE html>
    <html>
      <head>
        <title>@PageData["Title"]</title>
        <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
      </head>
      <body>
        <div id="header">
          @RenderSection("header")
        </div>
          @if (PageData["ShowList"] == true) {
              <div id="list">
                @RenderPage("~/Shared/_List.cshtml")
              </div>
          }
        <div id="main">
          @RenderBody()
        </div>
        <div id="footer">
          <p>&copy; 2012 Contoso Pharmaceuticals. All rights reserved.</p>
        </div>
      </body>
    </html>
    

    レイアウト ページには、PageData プロパティからタイトル値を取得する <title> 要素に式が含まれています。 また、PageData プロパティの ShowList 値を使用して、リスト コンテンツ ブロックを表示するかどうかを決定します。

  3. Shared フォルダーで、_List.cshtml という名前のファイルを作成し、既存の内容を次のように置き換えます。

    <ul>
      <li>Lorem</li>
      <li>Ipsum</li>
      <li>Dolor</li>
      <li>Consecte</li>
      <li>Eiusmod</li>
      <li>Tempor</li>
      <li>Incididu</li>
    </ul>
    
  4. ブラウザーで Content3.cshtml ページを実行します。 ページが表示され、ページの左側にリストが表示され、下部に [リストの非表示] ボタンが表示されます。

    Screenshot showing the page that includes the list and a button that says 'Hide List'.

  5. [リストの非表示] をクリックします。 リストが表示されなくなり、ボタンが [リストの表示] に変わります。

    Screenshot showing the page that does not include the list and a button that says 'Show List'.

  6. [リストの表示] ボタンをクリックすると、リストが再び表示されます。

その他のリソース

ASP.NET Web ページのサイト全体の動作のカスタマイズ