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

Tom FitzMacken

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

学習内容:

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

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

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

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

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

このチュートリアルは、ASP.NET Web ページ 2 でも動作します。

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

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

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

RenderPage メソッドが参照先ページを現在のページに挿入する方法を示す概念図。

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

RenderPage メソッドの呼び出しを含むページを実行した結果のブラウザーのページを示すスクリーンショット。

  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. [共有] フォルダーに、_Header.cshtml という名前のファイルを作成します。

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

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

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

  6. [共有] フォルダーで、_Footer.cshtml という名前のファイルを作成し、コンテンツを次のように置き換えます。

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

    <!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. ブラウザーで、ページ ソースを表示します。 (たとえば、インターネット エクスプローラーでページを右クリックし、[ソースの表示] をクリックします)。

    これにより、ブラウザーに送信される 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 ページが完了すると、ブラウザーに送信されます。

RenderBody メソッドの呼び出しを含むページを実行した結果のブラウザーのページを示すスクリーンショット。

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

  1. Web サイトの [共有 ] フォルダーに 、_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. [共有] フォルダーで、_Header2.cshtml という名前のファイルを作成し、既存のコンテンツを次のように置き換えます。

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

  5. [スタイル] フォルダーで、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 で定義されているテキスト (コンテンツ) が使用されます。

    [スクリーンショットは、ブラウザーで Content 1 dot CSHTML を実行している状態を示しています。]

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

    Note

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

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

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

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

RenderSection メソッドが参照セクションを現在のページに挿入する方法を示す概念図。

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

  1. [共有] フォルダーに、_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 を実行します。

    RenderSection メソッドの呼び出しを含むページを実行した結果のページをブラウザーで示すスクリーンショット。

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

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

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

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

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

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

    RenderSection メソッドを呼び出すページを実行しても、対応するセクションが指定されていない場合に発生するエラーを示すスクリーンショット。

  3. [共有] フォルダーで、_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 値には、コンテンツ ページ内の他のセクションや追加のコンテンツ ブロックからアクセスすることもできます。

コンテンツ ページで PageData ディクショナリを設定し、その情報をレイアウト ページに渡す方法を示す概念図。

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

[[Passing Data]\(データの受け渡し\) ページを示すスクリーンショット。

  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 ページの本文のブロックによって、true に設定されているかどうか PageData["ShowList"] に応じて、表示するフォームが決まります。

  2. [共有] フォルダーで、_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>
    

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

  3. [共有] フォルダーで、_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 ページを実行します。 ページが表示され、ページの左側にリストが表示され、下部に [リストを非表示] ボタンが表示されます。

    リストを含むページと、

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

    リストを含まないページと、[リストの表示] というボタンを示すスクリーンショット。

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

その他のリソース

ASP.NET Web ページのSite-Wide動作のカスタマイズ