ビュー マスター ページにデータを渡す (C#)

提供元: Microsoft

PDF のダウンロード

このチュートリアルの目的は、コントローラーからビュー マスター ページにデータを渡す方法を説明することです。 ビュー マスター ページにデータを渡す 2 つの方法について説明します。 最初に、アプリケーションの保守が困難になる、簡単なソリューションについて説明します。 次に、必要な初期作業が若干増えるものの、アプリケーションの保守がずっと容易になる、はるかに優れたソリューションについて説明します。

ビュー マスター ページにデータを渡す

このチュートリアルの目的は、コントローラーからビュー マスター ページにデータを渡す方法を説明することです。 ビュー マスター ページにデータを渡す 2 つの方法について説明します。 最初に、アプリケーションの保守が困難になる、簡単なソリューションについて説明します。 次に、必要な初期作業が若干増えるものの、アプリケーションの保守がずっと容易になる、はるかに優れたソリューションについて説明します。

問題

映画データベース アプリケーションを構築していて、アプリケーションのすべてのページに映画カテゴリのリストを表示する必要があるとします (図 1 を参照)。 また、映画カテゴリのリストをデータベース テーブルに格納するとします。 この場合、それらのカテゴリをデータベースから取得し、ビュー マスター ページ内に映画カテゴリのリストを表示するのが合理的です。

Displaying movie categories in a view master page

図 01: ビュー マスター ページでの映画カテゴリの表示 (クリックするとフルサイズの画像が表示されます)

ここで問題となることがあります。 マスター ページで映画カテゴリのリストを取得するにはどうすればよいでしょうか。 マスター ページでモデル クラスのメソッドを直接呼び出したくなります。 つまり、マスター ページでじかにデータベースからデータを取得するためのコードを含めたくなります。 ただし、MVC コントローラーをバイパスしてデータベースにアクセスすると、MVC アプリケーションを構築する主な利点の 1 つである、明確な関心の分離に違反します。

MVC アプリケーションでは、MVC ビューと MVC モデル間のすべてのやり取りを MVC コントローラーに処理させる必要があります。 この関心の分離により、アプリケーションはいっそう保守が容易で、適応性があり、テストしやすいものになります。

MVC アプリケーションでは、ビューに渡すすべてのデータ (ビュー マスター ページを含む) を、コントローラー アクションによってビューに渡す必要があります。 さらに、ビュー データを利用してデータを渡す必要があります。 このチュートリアルの残りの部分では、ビュー マスター ページにビュー データを渡す 2 つの方法について説明します。

簡単なソリューション

まず、コントローラーからビュー マスター ページにビュー データを渡すための最も簡単なソリューションから始めます。 最も簡単なソリューションは、コントローラー アクションのたびにマスター ページのビュー データを渡すことです。

リスト 1 のコントローラーについて考えてみましょう。 Index() および Details() という名前の 2 つのアクションを公開します。 Index() アクション メソッドは、Movies データベース テーブル内のすべての映画を返します。 Details() アクション メソッドは、特定の映画カテゴリ内のすべての映画を返します。

リスト 1 – Controllers\HomeController.cs

using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{
     [HandleError]
     public class HomeController : Controller
     {
          private MovieDataContext _dataContext = new MovieDataContext();

          /// <summary>

          /// Show list of all movies
          /// </summary>
          public ActionResult Index()
          {
               ViewData["categories"] = from c in _dataContext.MovieCategories 
                         select c;
               ViewData["movies"] = from m in _dataContext.Movies 
                         select m;
               return View();
          }

          /// <summary>
          /// Show list of movies in a category
          /// </summary>

          public ActionResult Details(int id)
          {
               ViewData["categories"] = from c in _dataContext.MovieCategories 
                         select c;
               ViewData["movies"] = from m in _dataContext.Movies 
                         where m.CategoryId == id
                         select m;
               return View();
          }
     }
}

Index() アクションと Details() アクションの両方で、データを表示するために 2 つの項目が追加されることに注意してください。 Index() アクションは、categories および movies という 2 つのキーを追加します。 categories キーは、ビュー マスター ページによって表示される映画カテゴリのリストを表しています。 movies キーは、Index ビュー ページによって表示される映画のリストを表しています。

Details() アクションも、categories および movies という名前の 2 つのキーを追加します。 categories キーは、やはり、ビュー マスター ページによって表示される映画カテゴリのリストを表しています。 movies キーは、Details ビュー ページによって表示される特定のカテゴリの映画のリストを表しています (図 2 を参照)。

The Details view

図 02: Details ビュー (クリックするとフルサイズの画像が表示されます)

Index ビューはリスト 2 に含まれています。 これは、ビュー データ内の映画項目によって表される映画のリストを反復処理するだけです。

リスト 2 – Views\Home\Index.aspx

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>

<%@ Import Namespace="MvcApplication1.Models" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">

<ul>

<% foreach (var m in (IEnumerable<Movie>)ViewData["movies"])
     { %>

     <li><%= m.Title %></li>

<% } %>
</ul>

</asp:Content>

ビュー マスター ページはリスト 3 に含まれています。 ビュー マスター ページは、ビュー データからのカテゴリ項目によって表されるすべての映画カテゴリを反復処理して表示します。

リスト 3 – Views\Shared\Site.master

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.Master.cs" Inherits="MvcApplication1.Views.Shared.Site" %>
<%@ Import Namespace="MvcApplication1.Models" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
     <title></title>
     <asp:ContentPlaceHolder ID="head" runat="server">

     </asp:ContentPlaceHolder>
</head>
<body>
     <div>
          <h1>My Movie Website</h1>

          <% foreach (var c in (IEnumerable<MovieCategory>)ViewData["categories"])
                           {%>

               <%= Html.ActionLink(c.Name, "Details", new {id=c.Id} ) %> 

          <% } %>


          <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">

          </asp:ContentPlaceHolder>
     </div>
</body>
</html>

すべてのデータが、ビュー データによってビューとビュー マスター ページに渡されます。 これは、マスター ページにデータを渡す正しい方法です。

では、このソリューションの何が問題なのでしょうか。 問題は、このソリューションが DRY (Don't Repeat Yourself) 原則に違反していることです。 コントローラー アクションのたびに、まったく同じ映画カテゴリのリストをビュー データに追加する必要があります。 アプリケーションに重複するコードがあると、アプリケーションの保守、適応、変更がはるかに困難になります。

優れたソリューション

このセクションでは、コントローラー アクションからビュー マスター ページにデータを渡すための、より優れた別のソリューションについて説明します。 コントローラー アクションのたびにマスター ページの映画カテゴリを追加する代わりに、ビュー データに映画カテゴリを 1 回だけ追加します。 ビュー マスター ページで使用されるすべてのビュー データは、Application コントローラーに追加されます。

ApplicationController クラスはリスト 4 に含まれています。

リスト 4 – Controllers\ApplicationController.cs

using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{
     public abstract class ApplicationController : Controller
     {
          private MovieDataContext _dataContext = new MovieDataContext();

          public MovieDataContext DataContext
          {
               get { return _dataContext; }
          }

          public ApplicationController()
          {
               ViewData["categories"] = from c in DataContext.MovieCategories 
                         select c;
          }

     }
}

リスト 4 の Application コントローラーについて、3 つの点に注目する必要があります。 1 つ目に、このクラスが System.Web.Mvc.Controller 基底クラスから継承されることに注目してください。 Application コントローラーはコントローラー クラスです。

2 つ目に、Application コントローラー クラスが抽象クラスであることに注目してください。 抽象クラスは、具象クラスで実装する必要があるクラスです。 Application コントローラーは抽象クラスであるため、クラスで定義されているメソッドを直接呼び出すことはできません。 Application クラスを直接呼び出そうとすると、"リソースが見つかりません" というエラー メッセージが表示されます。

3 つ目に、Application コントローラーに、映画カテゴリのリストをビュー データに追加するコンストラクターが含まれていることに注目してください。 Application コントローラーから継承されるすべてのコントローラー クラスが、Application コントローラーのコンストラクターを自動的に呼び出します。 Application コントローラーから継承されるコントローラーでアクションを呼び出すたびに、映画カテゴリがビュー データに自動的に含められます。

リスト 5 の Movies コントローラーは、Application コントローラーから継承されます。

リスト 5 – Controllers\MoviesController.cs

using System.Linq;
using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
     public class MoviesController : ApplicationController
     {
          /// <summary>

          /// Show list of all movies
          /// </summary>
          public ActionResult Index()
          {
               ViewData["movies"] = from m in DataContext.Movies 
                         select m;
               return View();
          }

          /// <summary>
          /// Show list of movies in a category
          /// </summary>

          public ActionResult Details(int id)
          {
               ViewData["movies"] = from m in DataContext.Movies
                         where m.CategoryId == id
                         select m;
               return View();
          }

     }
}

Movies コントローラーは、前のセクションで説明した Home コントローラーと同様に、Index() および Details() という名前の 2 つのアクション メソッドを公開します。 Index() または Details() メソッドのいずれかで、ビュー マスター ページによって表示される映画カテゴリのリストがビュー データに追加されないことに注目してください。 Movies コントローラーは Application コントローラーから継承されるため、映画カテゴリのリストはビュー データに自動的に追加されます。

ビュー マスター ページのビュー データを追加するこのソリューションでは、DRY (Don't Repeat Yourself) 原則に違反しないことに注目してください。 映画カテゴリのリストをビュー データに追加するコードは、1 つの場所、つまり Application コントローラーのコンストラクターにのみ含まれています。

まとめ

このチュートリアルでは、コントローラーからビュー マスター ページにビュー データを渡す 2 つの方法について説明しました。 最初に、簡単でも、保守が困難になる方法を検討しました。 最初のセクションでは、アプリケーションでコントローラー アクションのたびにビュー マスター ページのビュー データを追加する方法について説明しました。 これは、DRY (Don't Repeat Yourself) 原則に違反しているため、良くない方法であると結論付けました。

次に、ビュー マスター ページで必要なデータをビュー データに追加するための、はるかに優れた方法を検討しました。 コントローラー アクションのたびにビュー データを追加する代わりに、Application コントローラー内でビュー データを 1 回だけ追加しました。 この方法により、ASP.NET MVC アプリケーションのビュー マスター ページにデータを渡す際の重複するコードを回避できます。