コントローラーとビューを使用し、リスティング/詳細 UI を実装する

提供元: Microsoft

PDF のダウンロード

これは、ASP.NET MVC 1 を使用して小規模で完全な Web アプリケーションを構築する方法を説明する無料の "NerdDinner" アプリケーション チュートリアルのステップ 4 です。

ステップ 4 では、NerdDinner サイトのディナー用に、モデルを利用してユーザーにデータをリスト表示したり、詳細をナビゲーションしたりするエクスペリエンスを提供するコントローラーをアプリケーションに追加する方法を示します。

ASP.NET MVC 3 を使用している場合は、MVC 3 の概要または MVC Music Store に関するチュートリアルに従うことをお勧めします。

NerdDinner ステップ 4: コントローラーとビュー

従来の Web フレームワーク (従来の ASP、PHP、ASP.NET Web フォームなど) では、通常、受信 URL はディスク上のファイルにマップされます。 たとえば、"/Products.aspx" や "/Products.php" などの URL に対する要求は、"Products.aspx" や "Products.php" ファイルによって処理される場合があります。

Web ベースの MVC フレームワークは、URL をサーバー コードに少し異なる方法でマップします。 受信 URL をファイルにマップするのではなく、URL をクラスのメソッドにマップします。 これらのクラスは "Controllers" と呼ばれ、受信 HTTP 要求の処理、ユーザー入力の処理、データの取得と保存、クライアントに送り返す応答の決定 (HTML の表示、ファイルのダウンロード、別の URL へのリダイレクトなど) を担当します。

NerdDinner アプリケーションの基本的なモデルを構築したので、次の手順では、それを利用するコントローラーをアプリケーションに追加して、ユーザーにサイト上の Dinners のデータ一覧/詳細ナビゲーション エクスペリエンスを提供します。

DinnersController コントローラーの追加

まず、Web プロジェクト内の "Controllers" フォルダーを右クリックし、[追加]->[コントローラー] メニュー コマンドを選択します (CTRL + M、CTRL + C を押してコマンドを実行することもできます)。

Screenshot of the Solution Explorer window showing the Controllers folder and the Add and Controller menu items highlighted in blue.

これにより、[コントローラーの追加] ダイアログが表示されます。

Screenshot of the Add Controller dialog showing the Controller Name field filled with the text Dinners Controller.

新しいコントローラーに "DinnersController" という名前を付け、[追加] ボタンをクリックします。 その後、Visual Studio は \Controllers ディレクトリの下に DinnersController.cs ファイルを追加します。

Screenshot of the Solution Explorer window showing the Dinner Controllers dot c s file highlighted in blue.

また、コード エディター内で新しい DinnersController クラスも開きます。

Index() および Details() アクション メソッドを DinnersController クラスに追加する

訪問者がこのアプリケーションを使用して、今後のディナーの一覧を参照できるようにし、リスト内の任意のディナーをクリックすると、それに関する具体的な詳細を表示できるようにしたいと考えています。 このために、アプリケーションから次の URL を発行します。

URL 目的
/Dinners/ 今後のディナーの HTML リストを表示する
/Dinners/Details/[id] URL に埋め込まれた "id" パラメーターによって示される特定のディナーに関する詳細を表示します。これは、データベース内のディナーの DinnerID と一致するものです。 たとえば、/Dinners/Details/2 は、DinnerID 値が 2 の Dinner に関する詳細を含む HTML ページを表示します。

次のように、DinnersController クラスに 2 つのパブリック "アクション メソッド" を追加することで、これらの URL の初期実装を公開します。

public class DinnersController : Controller {

    //
    // HTTP-GET: /Dinners/

    public void Index() {
        Response.Write("<h1>Coming Soon: Dinners</h1>");
    }

    //
    // HTTP-GET: /Dinners/Details/2

    public void Details(int id) {
        Response.Write("<h1>Details DinnerID: " + id + "</h1>");
    }
}

その後、NerdDinner アプリケーションを実行し、ブラウザーを使用してそれらを呼び出します。 "/Dinners/" URL を入力すると、Index() メソッドが実行され、次の応答が返されます。

Screenshot of the response window generated from running the NerdDinner application, showing the text Coming Soon: Dinners.

"/Dinners/2" URL を入力すると、Details() メソッドが実行され、次の応答が返されます。

Screenshot of the response window generated from running the NerdDinner application, showing the text Details Dinner I D: 2.

MVC ASP.NET は、DinnersController クラスを作成し、それらのメソッドを呼び出すことをどのように理解しているのでしょうか? そのことを理解するために、ルーティングのしくみを簡単に見てみましょう。

ASP.NET MVC ルーティングについて

ASP.NET MVC には、URL をコントローラー クラスにマップする方法を柔軟に制御できる強力な URL ルーティング エンジンが含まれています。 これにより、ASP.NET MVC が、作成するコントローラー クラスやそれに対して呼び出すメソッドを選択する方法をカスタマイズすることができます。また、変数が自動的に URL Querystring から解析され、パラメータ変数としてメソッドに渡されるさまざまな仕組みを構成できます。 これにより、SEO (検索エンジンの最適化) 用にサイトを完全に最適化し、アプリケーションから必要な URL 構造を公開する柔軟性が得られます。

既定では、新しい ASP.NET MVC プロジェクトには、既に登録されている構成済みの一連の URL ルーティング規則が付属しています。 これにより、明示的に何も構成しなくても、アプリケーションを簡単に開始できます。 既定のルーティング規則の登録は、プロジェクトの "Application" クラス内にあります。プロジェクトのルートにある "Global.asax" ファイルをダブルクリックして開くことができます。

Screenshot of the Solution Explorer window showing the Global dot a s a x file highlighted in blue and circled in red.

既定の ASP.NET MVC ルーティング規則は、このクラスの "RegisterRoutes" メソッド内に登録されています。

public void RegisterRoutes(RouteCollection routes) {

    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",                                       // Route name
        "{controller}/{action}/{id}",                    // URL w/ params
        new { controller="Home", action="Index",id="" }  // Param defaults
    );
}

上記の "routes.MapRoute()" メソッド呼び出しは、URL 形式 "/{controller}/{action}/{id}"を使用して受信 URL をコントローラー クラスにマップする既定のルーティング規則を登録します ("controller" はインスタンス化するコントローラー クラスの名前、 "action" は呼び出すパブリック メソッドの名前、"id" はメソッドに引数として渡すことができる URL 内に埋め込まれた省略可能なパラメーターです)。 "MapRoute()" メソッド呼び出しに渡される 3 番目のパラメーターは、URL にコントローラー/アクション/ID 値がない場合、それらに使用する既定値のセットです (Controller = "Home",Action="Index", Id="")。

既定の "/{controllers}/{action}/{id}" ルーティング規則を使用してさまざまな URL がどのようにマップされるかを示す表を次に示します。

URL コントローラー クラス アクション メソッド 渡されたパラメータ
/Dinners/Details/2 DinnersController Details(id) id=2
/Dinners/Edit/5 DinnersController Edit(id) id=5
/Dinners/Create DinnersController Create() 該当なし
/Dinners DinnersController Index() 該当なし
/Home HomeController Index() 該当なし
/ HomeController Index() 該当なし

最後の 3 行では、使用されている既定値 (Controller = Home、Action = Index、Id = "") が表示されます。 アクション名が指定されていない場合、"Index" メソッドが既定のアクション名として登録されているため、"/Dinners" および "/Home" URL では、そのコントローラー クラスで Index() アクション メソッドが呼び出されます。 コントローラーが指定されていない場合、"Home" コントローラーが既定のコントローラーとして登録されているため、"/" URL では HomeController が作成され、それに対する Index() アクション メソッドが呼び出されます。

これらの既定の URL ルーティング規則を使いたくない場合は、上記の RegisterRoutes メソッド内でそれらを編集するだけで、簡単に変更できます。 ただし、NerdDinner アプリケーションでは、既定の URL ルーティング規則を変更せず、そのまま使用します。

DinnersController からの DinnerRepository の使用

DinnersController の Index() および Details() アクション メソッドの現在の実装を、モデルを使用する実装に置き換えてみましょう。

前に構築した DinnerRepository クラスを使用して、動作を実装します。 まず、"NerdDinner.Models" 名前空間を参照する "using" ステートメントを追加し、DinnerController クラスのフィールドとして DinnerRepository のインスタンスを宣言します。

この章の後半では、"依存関係の挿入" の概念を紹介し、コントローラーがより優れた単体テストを可能にする DinnerRepository への参照を取得する別の方法を紹介しますが、現時点では、DinnerRepository のインスタンスを次のようにインラインで作成します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using NerdDinner.Models;

namespace NerdDinner.Controllers {

    public class DinnersController : Controller {

        DinnerRepository dinnerRepository = new DinnerRepository();

        //
        // GET: /Dinners/

        public void Index() {
            var dinners = dinnerRepository.FindUpcomingDinners().ToList();
        }

        //
        // GET: /Dinners/Details/2

        public void Details(int id) {
            Dinner dinner = dinnerRepository.GetDinner(id);
        }
    }
}

これで、取得したデータ モデル オブジェクトを使用して HTML 応答を生成する準備ができました。

コントローラーでのビューの使用

アクション メソッド内でコードを記述して HTML をアセンブルし、 Response.Write() ヘルパー メソッドを使用してクライアントに送り返すこともできますが、そのアプローチはすぐに、かなり扱いにくくなります。 より良いアプローチは、DinnersController アクション メソッド内でのみアプリケーションとデータ ロジックを実行し、HTML 応答を HTML 表現の出力を担当する別の "ビュー" テンプレートに HTML 応答をレンダリングするために必要なデータを渡すことです。 後で説明するように、"ビュー" テンプレートは、通常、HTML マークアップと埋め込みレンダリング コードの組み合わせを含むテキスト ファイルです。

コントローラー ロジックをビュー レンダリングから分離することには、いくつかの大きな利点があります。 特に、アプリケーション コードと UI の書式設定/レンダリング コードの間に明確な "懸念事項の分離" が適用されるため、便利です。 これにより、アプリケーション ロジックを UI レンダリング ロジックから分離して、簡単に単体テストが行えます。 アプリケーション コードを変更せず、後で UI レンダリング テンプレートを簡単に変更できるようになります。 また、開発者とデザイナーがプロジェクトで共同作業を容易に行うことができます。

DinnersController クラスを更新して、2 つのアクション メソッドのメソッド シグネチャを戻り値の型 "void" から戻り値の型 "ActionResult" に変更することで、ビュー テンプレートを使用して HTML UI 応答を返す必要があることを示すことができます。 次に、Controller 基底クラスの View() ヘルパー メソッドを呼び出して、次のように "ViewResult" オブジェクトを返すことができます。

public class DinnersController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // GET: /Dinners/

    public ActionResult Index() {

        var dinners = dinnerRepository.FindUpcomingDinners().ToList();

        return View("Index", dinners);
    }

    //
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View("Details", dinner);
    }
}

上で使用している View() ヘルパー メソッドのシグネチャは次のようになります。

Screenshot of the View helper method with the text View Result View (string view Name, object model).

View() ヘルパー メソッドの最初のパラメーターは、HTML 応答のレンダリングに使用するビュー テンプレート ファイルの名前です。 2 番目のパラメーターは、HTML 応答をレンダリングするためにビュー テンプレートに必要なデータを含むモデル オブジェクトです。

Index() アクション メソッド内では、View() ヘルパー メソッドを呼び出し、"Index" ビュー テンプレートを使用してディナーの HTML リストをレンダリングすることを示しています。 ビュー テンプレートに、Dinner オブジェクトのシーケンスを渡し、それからリストを生成します。

//
    // GET: /Dinners/

    public ActionResult Index() {
    
        var dinners = dinnerRepository.FindUpcomingDinners().ToList();
        
        return View("Index", dinners);
    }

Details() アクション メソッド内では、URL 内で指定された ID を使用して Dinner オブジェクトを取得しようとします。 有効な Dinner が見つかった場合は、View() ヘルパー メソッドを呼び出し、"Details" ビュー テンプレートを使用して取得した Dinner オブジェクトをレンダリングすることを示します。 無効なディナーが要求された場合は、"NotFound" ビュー テンプレート (および、テンプレート名のみを持つ View() ヘルパー メソッドのオーバーロードされたバージョン) を使用してそのディナーは存在しないことを示すわかりやすいエラー メッセージをレンダリングします。

//
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.FindDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View("Details", dinner);
    }

では、"NotFound"、"Details"、および "Index" ビュー テンプレートを実装しましょう。

"NotFound" ビュー テンプレートの実装

まず、"NotFound" ビュー テンプレートを実装します。これは、要求されたディナーが見つからないことを示すわかりやすいエラー メッセージを表示します。

コントローラー アクション メソッド内にテキスト カーソルを置き、右クリックして [ビューの追加] メニュー コマンドを選択して新しいビュー テンプレートを作成します (Ctrl + M、Ctrl + V キーを押してこのコマンドを実行することもできます)。

Screenshot of the project with the right-click menu item Add View highlighted in blue and circled in red.

これにより、次のように [ビューの追加] ダイアログが表示されます。 既定では、ダイアログは、作成するビューの名前を、ダイアログの起動時にカーソルが置かれたアクション メソッドの名前と一致するように事前設定します (この場合は "Details")。 最初に実装するのは "NotFound" テンプレートなので、このビュー名をオーバーライドし、代わりに "NotFound" に設定します。

Screenshot of the Add View window with the View name field set to Not Found, the Select master page box checked, and the Content Place Holder I D set to Main Content.

[追加] ボタンをクリックすると、Visual Studio によって "\Views\Dinners" ディレクトリ内に新しい "NotFound.aspx" ビュー テンプレートが作成されます (ディレクトリがまだ存在しない場合、ディレクトリも作成されます)。

Screenshot of the Solution Explorer window folder hierarchy with the Not Found dot a s p x file highlighted in blue.

また、コード エディター内に新しい "NotFound.aspx" ビュー テンプレートも開きます。

Screenshot of the code editor window with the Not Found dot a s p x file opened within the code editor.

既定では、ビュー テンプレートには、コンテンツとコードを追加できる 2 つの "コンテンツ領域" があります。 1 つ目の領域では、返される HTML ページの "タイトル" をカスタマイズできます。 2 つ目の領域では、返される HTML ページの "メイン コンテンツ" をカスタマイズできます。

"NotFound" ビュー テンプレートを実装するために、いくつかの基本的なコンテンツを追加します。

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Dinner Not Found
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Dinner Not Found</h2>

    <p>Sorry - but the dinner you requested doesn't exist or was deleted.</p>

</asp:Content>

その後、ブラウザーで試すことができます。 このために、"/Dinners/Details/9999" URL を要求してみます。 これは、データベースに現在存在しないディナーを参照しているため、DinnersController.Details() アクション メソッドは "NotFound" ビュー テンプレートをレンダリングします。

Screenshot of the My MVC Application window with the / Dinners / Details / 9999 U R L in the address box circled in red.

上記のスクリーン ショットから分かることの 1 つは、基本的なビュー テンプレートが、画面上のメインコンテンツ周りの一連の HTML を継承していることです。 これは、ビュー テンプレートでは、サイト上のすべてのビューに一貫したレイアウトを適用できる "マスター ページ" テンプレートを使用しているためです。 マスター ページの動作については、このチュートリアルの後半で説明します。

"Details" ビュー テンプレートの実装

ここでは、"詳細" ビュー テンプレートを実装しましょう。これにより、1 つの Dinner モデルに対して HTML が生成されます。

これを行うには、Details アクション メソッド内にテキスト カーソルを置き、右クリックして [表示の追加] メニュー コマンドを選択します (または、Ctrl + M キー、Ctrl + V キーを押します)。

Screenshot of the code editor window showing the right click menu item Add View dot dot dot highlighted in red.

[ビューの追加] ダイアログが表示されます。 既定のビュー名 ("Details") をそのまま使用します。 また、ダイアログで [厳密に型指定されたビューの作成] チェックボックスを選択し、コントローラーからビューに渡すモデルの種類の名前を選択します (コンボ ボックス ドロップダウンを使用)。 このビューでは、Dinner オブジェクトを渡します (この型の完全修飾名は "NerdDinner.Models.Dinner" です)。

Screenshot of the Add View window with the View content dropdown set to Details and the View data class set to Nerd Dinner dot Models dot Dinner.

"空のビュー" を作成した前のテンプレートとは異なり、今回は "Details" テンプレートを使用してビューを自動的に "スキャフォールディング" します。 これは、上記のダイアログで [コンテンツの表示] ドロップダウンを変更することで指定できます。

"スキャフォールディング" は、渡す Dinner オブジェクトに基づいて、詳細ビュー テンプレートの初期実装を生成します。 これは、ビュー テンプレートの実装をすばやく開始する簡単な方法となります。

[追加] ボタンをクリックすると、Visual Studio によって "\Views\Dinners" ディレクトリ内に新しい "DinnerForm.ascx" ビュー テンプレートが作成されます。

Screenshot of the Solution Explorer window showing the folder hierarchy with the Dinners folder highlighted in blue.

また、コード エディター内に新しい "Details.aspx" ビュー テンプレートも開きます。 内容には、Dinner モデルに基づく詳細ビューの初期スキャフォールディング実装が含まれます。 スキャフォールディング エンジンでは、.NET リフレクションを使用して、渡されたクラスで公開されているパブリック プロパティを確認し、検出された型それぞれに基づいて適切なコンテンツを追加します。

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Details
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Details</h2>

    <fieldset>
        <legend>Fields</legend>
        <p>
            DinnerID:
            <%=Html.Encode(Model.DinnerID) %>
        </p>
        <p>
            Title:
            <%=Html.Encode(Model.Title) %>
        </p>
        <p>
            EventDate:
            <%= Html.Encode(String.Format("{0:g}", Model.EventDate)) %>
        </p>
        <p>
            Description:
            <%=Html.Encode(Model.Description) %>
        </p>
        <p>
            HostedBy:
            <%=Html.Encode(Model.HostedBy) %>
        </p>
        <p>
            ContactPhone:
            <%=Html.Encode(Model.ContactPhone) %>
        </p>
        <p>
            Address:
            <%=Html.Encode(Model.Address) %>
        </p>
        <p>
            Country:
            <%=Html.Encode(Model.Country) %>
        </p>
        <p>
            Latitude:
            <%= Html.Encode(String.Format("{0:F}",Model.Latitude)) %>
        </p>
        <p>
            Longitude:
            <%= Html.Encode(String.Format("{0:F}",Model.Longitude)) %>
        </p>
    </fieldset>
    
    <p>
        <%=Html.ActionLink("Edit","Edit", new { id=Model.DinnerID }) %>|
        <%=Html.ActionLink("Back to List", "Index") %>
    </p>
    
</asp:Content>

"/Dinners/Details/1" URL を要求すると、ブラウザーでこの "詳細" スキャフォールディングの実装がどのように表示されるかを確認できます。 この URL を使用すると、最初にデータベースを作成したときに手動でデータベースに追加したディナーのいずれかが表示されます。

Screenshot of the application response window showing the / Dinners / Details / 1 U R L circled in red in the address box.

これにより、すぐに稼働させ、Details.aspx ビューの初期実装を示すことができます。 その後それを調整して、満足できるまで UI をカスタマイズできます。

Details.aspx テンプレートをより詳しく見ると、静的 HTML と埋め込みレンダリング コードが含まれていることがわかります。 <% %> コード ナゲットはビュー テンプレートのレンダリング時にコードを実行し、<%= %> コード ナゲットはそれらに含まれるコードを実行し、結果をテンプレートの出力ストリームにレンダリングします。

ビュー内には、厳密に型指定された "Model" プロパティを使用してコントローラーから渡された "Dinner" モデル オブジェクトにアクセスするコードを記述できます。 Visual Studio では、エディター内でこの "Model" プロパティにアクセスするときに、完全なコード intellisense が提供されます。

Screenshot of the code editor window showing a dropdown list with the item Description highlighted in blue.

最終的な Details ビュー テンプレートのソースを次のように調整してみましょう。

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Dinner: <%=Html.Encode(Model.Title) %>
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2><%=Html.Encode(Model.Title) %></h2>
    <p>
        <strong>When:</strong> 
        <%=Model.EventDate.ToShortDateString() %> 

        <strong>@</strong>
        <%=Model.EventDate.ToShortTimeString() %>
    </p>
    <p>
        <strong>Where:</strong> 
        <%=Html.Encode(Model.Address) %>,
        <%=Html.Encode(Model.Country) %>
    </p>
     <p>
        <strong>Description:</strong> 
        <%=Html.Encode(Model.Description) %>
    </p>       
    <p>
        <strong>Organizer:</strong> 
        <%=Html.Encode(Model.HostedBy) %>
        (<%=Html.Encode(Model.ContactPhone) %>)
    </p>
    
    <%= Html.ActionLink("Edit Dinner", "Edit", new { id=Model.DinnerID })%> |
    <%= Html.ActionLink("Delete Dinner","Delete", new { id=Model.DinnerID})%>   
     
</asp:Content>

"/Dinners/Details/1" URL に再度アクセスすると、次のようにレンダリングされます。

Screenshot of the application response window showing the new stylization of the dot NET Futures view.

"Index" ビュー テンプレートの実装

次に、"Index" ビュー テンプレートを実装しましょう。これにより、今後のディナーの一覧が生成されます。 これを行うには、Index アクション メソッド内にテキスト カーソルを置き、右クリックして [表示の追加] メニュー コマンドを選択します (または、Ctrl + M キー、Ctrl + V キーを押します)。

[ビューの追加] ダイアログでは、"Index" という名前のビュー テンプレートを保持し、[厳密に型指定されたビューを作成する] チェック ボックスをオンにします。 今回は、"List" ビュー テンプレートを自動的に生成し、ビューに渡されるモデルの種類には [NerdDinner.Models.Dinner] を選択します ("List" スキャフォールディングを作成していることを示しているため、[ビューの追加] ダイアログでは、コントローラーからビューに Dinner オブジェクトのシーケンスが渡されていると見なされます)。

Screenshot of the Add View window with the View name set to Index, the Create a strongly-typed view box ticked, and the Select master page box ticked.

[追加] ボタンをクリックすると、Visual Studio によって "\Views\Dinners" ディレクトリ内に新しい "Index.aspx" ビュー テンプレート ファイルが作成されます。 ビューに渡す Dinner の HTML テーブルの一覧を提供する初期実装が "スキャフォールディング" されます。

アプリケーションを実行して "/Dinners/" URL にアクセス すると、次のようにディナーの一覧がレンダリングされます。

Screenshot of the application response window showing the list of dinners in a grid layout after the Add View update.

上記のテーブル ソリューションは、ディナー データのグリッド状のレイアウトを提供します。これは、消費者向けの Dinner リストには適していません。 Index.aspx ビュー テンプレートを更新し、それを変更して少ないデータの列で一覧表示し、次のコードを使用してテーブルの代わりに <ul> 要素を使用してレンダリングします。

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Upcoming Dinners</h2>

    <ul>
        <% foreach (var dinner in Model) { %>
        
            <li>                 
                <%=Html.Encode(dinner.Title) %>            
                on 
                <%=Html.Encode(dinner.EventDate.ToShortDateString())%>
                @
                <%=Html.Encode(dinner.EventDate.ToShortTimeString())%>
            </li>
            
        <% } %>
    </ul>
    
</asp:Content>

モデル の各ディナーをループ処理する際に、上記の foreach ステートメント内で "var" キーワードを使用しています。 C# 3.0 に慣れていないユーザーは、"var" を使用することで、ディナー オブジェクトは遅延バインドされると考えるかもしれません。 そうではなく、コンパイラは、厳密に型指定された "Model" プロパティ ("IEnumerable<Dinner>" 型) に対して型推論を使用し、ローカルの "dinner" 変数を Dinner 型としてコンパイルしています。つまり、コード ブロック内で完全な IntelliSense とコンパイル時のチェックが行われます。

Screenshot of the code editor window showing a dropdown menu with the Address list item highlighted in a gray dotted box.

ブラウザーの /Dinners URL で 更新をクリックすると、更新されたビューは次のようになります。

Screenshot of the application response window showing a list of upcoming dinners after the refresh command.

前よりも良くなりましたが、まだ完全ではありません。 最後の手順では、エンドユーザーがリスト内の個々のディナーをクリックして、その詳細を表示できるようにします。 これを実装するには、DinnersController の Details アクション メソッドにリンクする HTML ハイパーリンク要素をレンダリングします。

これらのハイパーリンクは、インデックス ビュー内で 2 つの方法のいずれかで生成できます。 1 つ目は、HTML <a> 要素を次のように手動で作成することです。その <a> 要素内に <% %> ブロックを埋め込みます。

Screenshot of the code editor window with the a class and percent block text highlighted and circled in red.

または、ASP.NET MVC 内のビルトイン "Html.ActionLink()" メソッドを活用することです。これは、プログラムによってコントローラー上の別のアクション メソッドに HTML <a> 要素を作成することをサポートしています。

<%= Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>

Html.ActionLink() ヘルパー メソッドの最初のパラメーターは表示するリンク テキスト (この場合はディナーのタイトル)、2 番目のパラメーターはリンクを生成するコントローラー アクション名 (この場合は Details メソッド)、3 番目のパラメーターはアクションに送信するパラメーターのセットです (プロパティ名/値を持つ匿名型として実装されます)。 このケースでは、リンク先のディナーの "id" パラメーターを指定します。また、ASP.NET MVC の既定の URL ルーティング規則が "{Controller}/{Action}/{id}" であるため、Html.ActionLink() ヘルパー メソッドは次の出力を生成します。

<a href="/Dinners/Details/1">.NET Futures</a>

Index.aspx ビューでは、Html.ActionLink() ヘルパー メソッドのアプローチを使用し、リスト内の各ディナーを適切な詳細 URL へリンクします。

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Upcoming Dinners
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Upcoming Dinners</h2>

    <ul>
        <% foreach (var dinner in Model) { %>
        
            <li>     
                <%=Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>
                on 
                <%=Html.Encode(dinner.EventDate.ToShortDateString())%>
                @
                <%=Html.Encode(dinner.EventDate.ToShortTimeString())%>
            </li>
            
        <% } %>
    </ul>
</asp:Content>

すると、/Dinners URL を入力した場合、ディナーリストは次のようになります。

Screenshot of the application response window that shows the upcoming dinners list with new links corresponding to the list items.

リスト内のディナーのいずれかをクリックすると、それに関する詳細が表示されます。

Screenshot of the application response window that shows the selected list item and details corresponding to it as entered into the database.

規則ベースの名前付けと \Views ディレクトリの構造

ASP.NET MVC アプリケーションの既定では、ビュー テンプレートの解決時、キソクースのディレクトリ命名構造を使用します。 これにより、開発者は Controller クラス内からビューを参照するときに、場所のパスに完全修飾名を使用する必要がなくなります。 ASP.NET MVC は既定で、アプリケーションの下にある *\Views[ControllerName]* ディレクトリ内のビュー テンプレート ファイルを検索します。

たとえば、今取り組んでいる DinnersController クラスでは、"Index"、"Details"、"NotFound" の 3 つのビュー テンプレートを明示的に参照しています。 MVC ASP.NET は既定で、アプリケーションルートディレクトリの 下にある \Views\Dinners ディレクトリ内でこれらのビューを検索します。

Screenshot of the Solution Explorer window showing the folder hierarchy with the Dinners folder highlighted in a blue rectangle.

上記について、現在、プロジェクト内に 3 つのコントローラー クラス (DinnersController、HomeController、AccountController - 最後の 2 つはプロジェクトの作成時に既定で追加されました) があり、\Views ディレクトリ内に 3 つのサブディレクトリ (コントローラーごとに 1 つ) がああります。

Home コントローラーと Account コントローラーから参照されるビューは、それぞれ、\Views\Home ディレクトリと \Views\Account ディレクトリからビュー テンプレートを自動的に解決します。 \Views\Shared サブディレクトリは、アプリケーション内の複数のコントローラー間で再利用されるビュー テンプレートを格納する方法を提供します。 mvc ASP.NET はビュー テンプレートの解決を試みる際、最初に \Views[Controller] 固有のディレクトリ内を確認し、ビュー テンプレートが見つからない場合は \Views\Shared ディレクトリ内 を確認します。

個々のビュー テンプレートに名前を付ける場合、推奨されるガイダンスは、ビュー テンプレートがレンダリングの要因となったアクション メソッドと共通の名前を使用することです。 たとえば、上記の "Index" アクション メソッドでは "Index" ビューを使用してビューの結果をレンダリングし、"Details" アクション メソッドは "Details" ビューを使用してその結果をレンダリングしています。 これにより、各アクションに関連付けられているテンプレートをすばやく簡単に確認できます。

ビュー テンプレートがコントローラーで呼び出されるアクション メソッドと同じ名前である場合、開発者はビュー テンプレート名を明示的に指定する必要はありません。 代わりに、モデル オブジェクトを (ビュー名を指定せずに) "View()" ヘルパー メソッドに渡すことができます。ASP.NET MVC は、ディスク上の \Views[ControllerName][ActionName] ビュー テンプレートを使用してレンダリングすることを自動的に推論します。

これにより、コントローラーのコードを少しクリーンアップし、コード内で名前を 2 回重複させないようにすることができます。

public class DinnersController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // GET: /Dinners/

    public ActionResult Index() {

        var dinners = dinnerRepository.FindUpcomingDinners().ToList();

        return View(dinners);
    }

    //
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View(dinner);
    }
}

上記のコードで、サイトの Dinner リストと詳細のエクスペリエンスを実装するために必要なすべてが揃いました。

次の手順

これで、素晴らしいディナーのブラウジング体験を構築できました。

次に、CRUD (作成、読み取り、更新、削除) データ フォーム編集のサポートを有効にしましょう。