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

Tom FitzMacken

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

ここでは、次の内容について学習します。

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

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

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

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

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

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

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

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

次の図は、コンテンツ ブロックの動作を示しています。 ブラウザーが 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 という名前のフォルダーを作成します。

    注意

    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 ページで、次に示すように、メソッドに 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.cshtmlRenderPage挿入した呼び出しは、ヘッダー ファイルとフッター ファイルの実際の内容に置き換えられました。

    <!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. ルート フォルダーに新しいフォルダーを作成し、スタイルという名前を付 けます

  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. を繰り返して、同じレイアウト ページを共有できる追加のコンテンツ ページを作成できます。

    注意

    フォルダー内のすべてのコンテンツ ページに対して同じレイアウト ページを自動的に使用できるように、サイトを設定できます。 詳細については、「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 つのレイアウト ページを共有できるが、特定のセクションのコンテンツがある場合とない場合がある複数のコンテンツ ページを定義できます。

  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 読み取ることができます。

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

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

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

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

  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動作のカスタマイズ