第1回 ASP.NET MVCフレームワーク 基本のキ:連載:ASP.NET MVC入門(4/5 ページ)
従来とはまったく異なる手法でASP.NET Webアプリを構築するASP.NET MVCとはいかなるものか? 新しいフレームワークを基礎から学ぶ。
ユーザー・パラメータを受け取る方法
ルーティング・ルールを理解したところで、先ほど保留にしておいたユーザー・パラメータをアクション・メソッドで受け取る方法について見てみよう。
アクション・メソッドでユーザー・パラメータを受け取るには、あらかじめ定義しておいたパラメータ名(デフォルトの設定では{id})と同名の仮引数をアクション・メソッドに追加するだけだ。
例えば、先ほどのIndexアクションでユーザー・パラメータを受け取れるようにするには、以下のようにコードを変更するだけだ(変更個所は太字で表している)。
public ActionResult Index(string id) {
ViewData["msg"] = "こんにちは、ASP.NET MVC!";
ViewData["id"] = String.Format("id値:{0}", id);
return View();
}
Function Index(ByVal id As String) As ActionResult
ViewData("msg") = "こんにちは、ASP.NET MVC!"
ViewData("id") = String.Format("id値:{0}", id)
Return View()
End Function
(上:HelloController.cs、下:HelloController.vb)
Indexアクションが正しくユーザー・パラメータを受け取れていることを確認するために、ビュー(Hello/Index.aspx)の方も書き換えておこう。
<div>
<%=Html.Encode(ViewData["msg"])%>
<br />
<%=Html.Encode(ViewData["id"])%>
</div>
<div>
<%=Html.Encode(ViewData("msg"))%>
<br />
<%=Html.Encode(ViewData("id"))%>
</div>
(上:C#用、下:VB用)
以上の手順を終えたら、再びサンプルを実行してみよう。デバッグ実行でブラウザを起動し、以下のようなアドレスを入力してほしい。
http://localhost:4419/Hello/Index/108
ブラウザの表示は次のようになるはずだ。
確かに、ユーザー・パラメータidの値(ここでは「108」)が取得できることが確認できるはずだ。もちろん、本来のアプリケーションでは、受け取ったid値に基づいてデータベース・アクセスなどの処理を行うことになるはずであるが、この辺は次回以降に譲り、本稿ではまずはここまでとしておく。
アクション・メソッドでポスト・データを取得する
アクション・メソッドで、ポスト・データやクエリ文字列を取得するのも、ほとんど同じ要領でできる。次に、以下のようなアプリケーションを作成してみよう。
それではさっそく、手順を見ていくことにする。
[1]アクション・メソッドを定義する
まずは、コントローラのコードから。アクション・メソッドは、先ほど作成したHelloコントローラに対して、追加で定義するものとする。ここで定義するのは、入力フォームを生成するための「Post()メソッド」と、フォームから入力された値を処理するための「Post(name)メソッド」である。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace MvcAppCs.Controllers {
public class HelloController : Controller{
……中略……
// 入力フォームを生成するためのPostメソッドを定義
public ActionResult Post() {
return View();
}
// [送信]ボタンをクリックしたときに呼び出される
// Postメソッドを定義
[AcceptVerbs(HttpVerbs.Post)] (1)
public ActionResult Post(String name) {
ViewData["msg"] =
String.Format("こんにちは、{0}さん!", name); (2)
return View("Result"); (3)
}
}
}
Public Class HelloController
Inherits System.Web.Mvc.Controller
……中略……
' 入力フォームを生成するためのPostメソッドを定義
Function Post() As ActionResult
Return View()
End Function
' [送信]ボタンをクリックしたときに呼び出されるPostメソッドを定義
<AcceptVerbs(HttpVerbs.Post)> _ (1)
Function Post(ByVal name As String) As ActionResult
ViewData("msg") = _
String.Format("こんにちは、{0}さん!", name) (2)
Return View("Result") (3)
End Function
End Class
(上:HelloControllet.cs、下:HelloController.vb)
Post()メソッドについては、特に解説すべき点はない。ことさらに行うべき処理がない場合、アクション・メソッドには、ただActionResultオブジェクトを返すためのコードを記述すればよいだけだ。
ここでは注目してほしいのは、ポスト・データが送信されたときに呼び出されるPost(name)メソッドである。
(1)HTTPメソッドによって処理を分岐するAcceptVerbs属性
アクションがHTTP GET経由で呼び出された(URLにより直接アクセスされた)か、HTTP POST経由で呼び出された(フォームからポストされた)かによって、処理を分岐したいというケースはよくあることだ。その方法としてまず思い付くのは、アクション・メソッドの中で、Request.HttpMethodプロパティの値によって処理を分けることだ。
If Request.HttpMethod = "POST" Then
' HTTP POSTの場合の処理
Else
' HTTP GETの場合の処理
End If
しかし、このような手法はコードの可読性や単体テストのやりやすさという意味で、いささか難がある。
これを解消するために、フォームを表示するためのHello/Inputアクション、結果を表示するためのHello/Resultアクションというように、別々のアクションを用意するという方法も考えられるかもしれない。しかし、この場合は、また別な問題に遭遇することになる。
1つに、Hello/Resultアクションに対して、エンドユーザーが直接にアクセスしてしまう可能性があるということだ。Hello/Resultアクションはフォームから呼び出されることを想定しているアクションであるから、これは予期せぬエラーの原因になるかもしれない(そうでなくても、意図した結果は表示されないだろう)。
さらに、Hello/Resultが検索エンジンのクローラによって収集されてしまう恐れがあるということだ。当然、Hello/Resultはクローラによって収集されてよいURIではなく、このようなURIが公開されていることは、SEO(Search Engine Optimization)という観点からも好ましい状態ではない。
これらの問題を解決するために提供されているのが「AcceptVerbs属性」だ。
AcceptVerbs属性を利用することで、そのアクション・メソッドがどのようなHTTPメソッドに対して呼び出されるかを明示的に宣言できる。リスト6では、Post(name)メソッドに「<AcceptVerbs(HttpVerbs.Post)>」が付与されているので、HTTP POST経由でHello/Postが呼び出された場合にのみPost(name)メソッドが、それ以外の場合で(多くはHTTP GET経由で)Hello/Postが呼び出された場合にはPost()メソッドが呼び出されることになる。
これによって、外部に公開するURIを分けることなく、かつ、それぞれのメソッドのコードもすっきりと表現できるわけだ。
[参考]ActionName属性
余談ではあるが、ActionName属性を利用することで、アクション・メソッドの名前と、外部に公開するアクション名とを別にすることもできる。
例えば、以下のように記述した場合には、アクション名は「Test」であると見なされる(この場合は、対応するビューも「Test.aspx」を用意する必要がある点に注意)
<ActionName("Test")> _
Function Index(ByVal id As String) As ActionResult
……後略……
(2)パラメータ値は同名の仮引数に展開される
ポスト・データやクエリ文字列も、ユーザー・パラメータと同じく、パラメータ名と同名の仮引数に展開される。この場合であれば、引数nameにフォーム要素nameから入力された値がセットされることになるわけだ。
ただし、ポスト・データやクエリ文字列の場合には、Requestプロパティ(正しくはRequestプロパティ経由で取得できるHttpRequestオブジェクト)を介してアクセスすることもできる。
例えば、リスト6の(2)は以下のように書き換えても同じ意味である*9。
ViewData("msg") = _
String.Format("こんにちは、{0}さん!", Request.Form("name"))
*9 厳密には少し違う。Requestプロパティでは取得したパラメータ値を必ずString型で返すのに対して、引数経由で取得したパラメータ値の型は、引数のデータ型に応じて変動する。
(3)アクション名とビュー名は一致していなくても構わない
先ほど、ビューの名前はアクション名に対応していなければならないと述べたが、厳密には、アクション名とビュー名は一致していなくても構わない。
もしもアクション名と異なるビューを呼び出したいという場合には、Viewメソッドを呼び出す際に、その引数としてビュー名を明記すればよいだけだ。これによって、Hello/Result.aspxがビューとして呼び出される。
Return View("Result")
[2]ビューを作成する
次に、ビューについて見ていこう。ビューとして用意しなければならないのは、Post()メソッドに対応するHello/Post.aspxと、Post(name)メソッドに対応するHello/Result.aspxである。
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!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>
</head>
<body>
<div>
<% using(Html.BeginForm()) {%>
<label for="name">名前:</label>
<%=Html.TextBox("name")%>
<input type="submit" value="送信" />
<% }%>
</div>
</body>
</html>
<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage" %>
<!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>ポスト・データの取得</title>
</head>
<body>
<div>
<% Using Html.BeginForm()%>
<label for="name">名前:</label>
<%=Html.TextBox("name")%>
<input type="submit" value="送信" />
<% End Using%>
</div>
</body>
</html>
(上:C#用、下:VB用)
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!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>
</head>
<body>
<div>
<%=Html.Encode(ViewData["msg"])%>
</div>
</body>
</html>
<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage" %>
<!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>ポスト・データの取得</title>
</head>
<body>
<div>
<%=Html.Encode(ViewData("msg"))%>
</div>
</body>
</html>
(上:C#用、下:VB用)
Hello/Result.aspxについては、特筆すべき点はないだろう。ここで注目してほしいのは、リスト7のHello/Post.aspxである。
先ほども述べたように、ビューではHTMLヘルパーを利用することで、ビューの実装を効率化できる。ここで使用しているのは、<form>要素を生成するBeginFormメソッドと、<input type="text">要素を生成するTextBoxメソッドである。
BeginFormメソッドは、Usingステートメントでもって宣言することで、Usingブロックがそのまま<form>〜</form>タグで置き換えられる仕組みだ。引数を省略した場合には、<form>タグのaction属性には現在のアクションがそのままセットされる。つまり、この例では以下のような<form>タグが生成されるはずだ。
<form action="/Hello/Post/" method="post">
もしもaction属性やmethod属性の値を変更したい場合には、BeginFormメソッドの引数でもって対応できる。例えば、以下はaction属性を「/Home/Process」、method属性を「get」にしたい場合のBeginFormメソッドの記述である。
<% Using Html.BeginForm("Process", "Home", FormMethod.Get)%>
TextBoxメソッドは、引数として最低限、id/name属性の値を指定する必要がある。つまり、サンプルの例では、以下のような<input type="text">タグが生成されるはずだ。
<input id="name" name="name" type="text" value="" />
もしもvalue属性をセットしたい場合には、第2引数で指定することもできる。
<%=Html.TextBox("name", "名なしの権兵衛")%>
以上を理解したら、再びサンプルを実行してみよう。デバッグ実行でブラウザを起動し、「http://localhost:4419/Hello/Post/」でアクセスしたときに、本節冒頭の図11のような結果が得られれば成功である。
Copyright© Digital Advantage Corp. All Rights Reserved.