ビュー マスター ページにデータを渡す (VB)
提供元: Microsoft
このチュートリアルの目的は、コントローラーからビュー マスター ページにデータを渡す方法を説明することです。 ビュー マスター ページにデータを渡す 2 つの方法を検討します。 最初に、アプリケーションの保守が困難になる、簡単なソリューションについて説明します。 次に、必要な初期作業が若干増えるものの、アプリケーションの保守がずっと容易になる、はるかに優れたソリューションを検討します。
ビュー マスター ページにデータを渡す
このチュートリアルの目的は、コントローラーからビュー マスター ページにデータを渡す方法を説明することです。 ビュー マスター ページにデータを渡す 2 つの方法を検討します。 最初に、アプリケーションの保守が困難になる、簡単なソリューションについて説明します。 次に、必要な初期作業が若干増えるものの、アプリケーションの保守がずっと容易になる、はるかに優れたソリューションを検討します。
問題
映画データベース アプリケーションを構築していて、アプリケーションのすべてのページに映画カテゴリの一覧を表示する必要があるとします (図 1 を参照)。 また、映画カテゴリの一覧をデータベース テーブルに格納するとします。 この場合、それらのカテゴリをデータベースから取得し、ビュー マスター ページ内に映画カテゴリの一覧を表示するのが理にかなっています。
図 01: ビュー マスター ページでの映画カテゴリの表示 (クリックするとフルサイズの画像が表示されます)
ここで問題となることがあります。 マスター ページで映画カテゴリの一覧をどのように取得すればよいでしょうか。 マスター ページでモデル クラスのメソッドを直接呼び出したくなります。 つまり、マスター ページでじかにデータベースからデータを取得するためのコードを含めたくなります。 ただし、MVC コントローラーをバイパスしてデータベースにアクセスすると、MVC アプリケーションを構築する主な利点の 1 つである、明確な関心の分離に違反します。
MVC アプリケーションでは、MVC ビューと MVC モデル間のすべてのやり取りを MVC コントローラーに処理させる必要があります。 この関心の分離により、アプリケーションはいっそう保守が容易で、適応性があり、テストしやすいものになります。
MVC アプリケーションでは、ビュー (ビュー マスター ページを含む) に渡すすべてのデータを、コントローラー アクションによってビューに渡す必要があります。 さらに、ビュー データを利用してデータを渡す必要があります。 このチュートリアルの残りの部分では、ビュー マスター ページにビュー データを渡す 2 つの方法を検討します。
簡単なソリューション
まず、コントローラーからビュー マスター ページにビュー データを渡すための最も簡単なソリューションから始めます。 最も簡単なソリューションでは、コントローラー アクションのたびにマスター ページのビュー データを渡します。
リスト 1 のコントローラーについて考えてみましょう。 Index()
および Details()
という名前の 2 つのアクションを公開します。 Index()
アクション メソッドは、Movies データベース テーブル内のすべての映画を返します。 Details()
アクション メソッドは、特定の映画カテゴリ内のすべての映画を返します。
リスト 1 – Controllers\HomeController.vb
<HandleError()> _
Public Class HomeController
Inherits System.Web.Mvc.Controller
Private _dataContext As New MovieDataContext()
''' <summary>
''' Show list of all movies
''' </summary>
Function Index()
ViewData("categories") = From c In _dataContext.MovieCategories _
Select c
ViewData("movies") = From m In _dataContext.Movies _
Select m
Return View()
End Function
''' <summary>
''' Show list of movies in a category
''' </summary>
Function Details(ByVal id As Integer)
ViewData("categories") = From c In _dataContext.MovieCategories _
Select c
ViewData("movies") = From m In _dataContext.Movies _
Where m.CategoryId = id _
Select m
Return View()
End Function
End Class
Index()
と Details()
の両方のアクションが、2 つの項目をビュー データに追加することに注目してください。 Index()
アクションは、categories および movies という 2 つのキーを追加します。 categories キーは、ビュー マスター ページで表示される映画カテゴリの一覧を表しています。 movies キーは、Index ビュー ページで表示される映画の一覧を表しています。
Details()
アクションも、categories および movies という名前の 2 つのキーを追加します。 categories キーは、やはり、ビュー マスター ページで表示される映画カテゴリの一覧を表しています。 movies キーは、Details ビュー ページで表示される特定のカテゴリの映画の一覧を表しています (図 2 を参照)。
図 02: Details ビュー (クリックするとフルサイズの画像が表示されます)
Index ビューはリスト 2 に含まれています。 これは、ビュー データ内の映画項目によって表される映画の一覧を反復処理するだけです。
リスト 2 – Views\Home\Index.aspx
<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="false" CodeBehind="Index.aspx.vb" Inherits="MvcApplication1.Index" %>
<%@ Import Namespace="MvcApplication1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<ul>
<% For Each m In ViewData("movies")%>
<li><%= m.Title %></li>
<% Next%>
</ul>
</asp:Content>
ビュー マスター ページはリスト 3 に含まれています。 ビュー マスター ページは、ビュー データからのカテゴリ項目によって表されるすべての映画カテゴリを反復処理して表示します。
リスト 3 – Views\Shared\Site.master
<%@ Master Language="VB" AutoEventWireup="false" CodeBehind="Site.Master.vb" Inherits="MvcApplication1.Site" %>
<%@ Import Namespace="MvcApplication1" %>
<!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>
<% For Each c In ViewData("categories")%>
<%=Html.ActionLink(c.Name, "Details", New With {.id = c.Id})%>
<% Next%>
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</body>
</html>
すべてのデータは、ビュー データによってビューとビュー マスター ページに渡されます。 これは、マスター ページにデータを渡す正しい方法です。
では、このソリューションの何が問題なのでしょうか。 問題は、このソリューションが DRY (Don't Repeat Yourself) 原則に違反していることです。 コントローラー アクションのたびに、まったく同じ映画カテゴリの一覧をビュー データに追加する必要があります。 アプリケーションに重複するコードがあると、アプリケーションの保守、適応、変更がはるかに困難になります。
優れたソリューション
このセクションでは、コントローラー アクションからビュー マスター ページにデータを渡すための、より優れた別のソリューションを検討します。 コントローラー アクションのたびにマスター ページの映画カテゴリを追加する代わりに、ビュー データに映画カテゴリを 1 回だけ追加します。 ビュー マスター ページで使用されるすべてのビュー データは、Application コントローラーに追加します。
ApplicationController クラスはリスト 4 に含まれています。
ApplicationController クラスはリスト 4 に含まれています。
リスト 4 – Controllers\ApplicationController.vb
Public MustInherit Class ApplicationController
Inherits System.Web.Mvc.Controller
Private _dataContext As New MovieDataContext()
Public ReadOnly Property DataContext() As MovieDataContext
Get
Return _dataContext
End Get
End Property
Sub New()
ViewData("categories") = From c In DataContext.MovieCategories _
Select c
End Sub
End Class
リスト 4 の Application コントローラーについて、3 つの点に注目する必要があります。 1 つ目に、このクラスが System.Web.Mvc.Controller 基底クラスから継承されることに注目してください。 Application コントローラーはコントローラー クラスです。
2 つ目に、Application コントローラー クラスが MustInherit クラスであることに注目してください。 MustInherit クラスは、具象クラスで実装する必要があるクラスです。 Application コントローラーは MustInherit クラスであるため、クラスで定義されているメソッドを直接呼び出すことはできません。 Application クラスを直接呼び出そうとすると、"リソースが見つかりません" というエラー メッセージが表示されます。
3 つ目に、Application コントローラーに、映画カテゴリの一覧をビュー データに追加するコンストラクターが含まれていることに注目してください。 Application コントローラーから継承されるすべてのコントローラー クラスは、Application コントローラーのコンストラクターを自動的に呼び出します。 Application コントローラーから継承されるコントローラーでアクションを呼び出すたびに、映画カテゴリがビュー データに自動的に含められます。
リスト 5 の Movies コントローラーは、Application コントローラーから継承されます。
リスト 5 – Controllers\MoviesController.vb
<HandleError()> _
Public Class MoviesController
Inherits ApplicationController
''' <summary>
''' Show list of all movies
''' </summary>
Function Index()
ViewData("movies") = From m In DataContext.Movies _
Select m
Return View()
End Function
''' <summary>
''' Show list of movies in a category
''' </summary>
Function Details(ByVal id As Integer)
ViewData("movies") = From m In DataContext.Movies _
Where m.CategoryId = id _
Select m
Return View()
End Function
End Class
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 アプリケーションのビュー マスター ページにデータを渡す際の重複するコードを回避できます。