ASP.NET MVC Frameworkをさわってみる 2
前回はページの表示のみだったので、次はURLにクエリを渡してみる。
単純に「Home/Index」というURLに対して、「message」というクエリ名で値を渡すとする。普通ならこのクエリの値はHttpRequestのQueryStringプロパティで取得するが、ASP.NET MVC Frameworkではこれを自動的にメソッドの引数にマップできる。
マップの仕方は単にURLにマップされたメソッド、ここでは「Index」メソッドにクエリ名と同じ名前の引数を定義するだけ。
App_Code/Controllers/HomeController.cs
[ControllerAction] public void Index(string message) { }
こうすることで自動的に「message」引数に同じ名前のクエリの値が渡される。(大文字小文字は区別されない)
この値を画面に表示する場合は、まず画面に値を引き渡す必要がある。それにはViewDataプロパティを使用する。
App_Code/Controllers/HomeController.cs
[ControllerAction] public void Index(string message) { ViewData["message"] = message; RenderView("Home"); }
このプロパティはキーと値のマップなので、ここでは「message」というキー名で値を設定している。この手法は従来のViewStateやSessionプロパティと同じやり方なので馴染みのある方法だろう。
そしてこれを画面側に表示する。
Views/Home/Home.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Home.aspx.cs" Inherits="Views_Home" %> <!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 runat="server"> <title>Home</title> </head> <body> <form id="form1" runat="server"> <div> <p><%= ViewData["message"] %></p> </div> </form> </body> </html>
このやり方でも別に問題は無いが、ViewDataは値とキーのマップであるため、値を取得する時は文字列でキー名を指定し、object型で値を取得するためタイプセーフとは言い難い。
しかし、以下のようにすればこれを解決できる。
Views/Home/Home.aspx.cs
using System; public partial class Views_Home : System.Web.Mvc.ViewPage<string> { }
画面が継承するViewPageクラスに引き渡す値の型を型パラメータとして指定する。こうすることでViewDataの型がマップから指定された型に変更される。
そうすると画面のコードを以下のように書き直す事ができる。
<p><%= ViewData %></p>
あとはコントローラメソッドからの値の引渡し方を変更する。
App_Code/Controllers/HomeController.cs
[ControllerAction] public void Index(string message) { RenderView("Home", (object)message); }
RenderViewメソッドの第二引数で引き渡す値を指定する。object型にキャストしているのはstring型で渡すと「RenderView(string viewName, string masterName)」という別のオーバーロードと解釈されてしまうため。
こうすることでタイプセーフに値を渡す事ができる。独自の型を定義して渡す場合などに重宝するだろう。
また、この方法では「/Home/Index?message=Hello」というURLでアクセスすることになるが、アプリケーションファイルに以下のようなRouteを定義することで「/Home/Index/Hello」というようなURLにする事もできる。
Global.asax
<%@ Application Language="C#" %> <%@ Import Namespace="System.Web.Mvc" %> <script RunAt="server"> void Application_Start(object sender, EventArgs e) { RouteTable.Routes.Add(new Route { // 独自のルート Url = "[controller]/[action]/[message]", Defaults = new { action = "Index", message = (string)null }, RouteHandler = typeof(MvcRouteHandler) }); RouteTable.Routes.Add(new Route { Url = "Default.aspx", Defaults = new { controller = "Home", action = "Index", id = (string)null }, RouteHandler = typeof(MvcRouteHandler) }); } </script>
この辺の自由度は素晴らしい。