第3回 ActionResultオブジェクトでアクション操作も自由自在:連載:ASP.NET MVC入門(1/5 ページ)
コントローラでのアクションの実行が完了すると、その結果はActionResultにまとめられる。そのさまざまな派生オブジェクトについて見ていこう。
本連載では、.NET Frameworkの新たなWebアプリケーション・フレームワークであるASP.NET MVCを基礎から解説している。前回までで、Model−View−Controllerを構成する基本的な要素、そして、アプリケーション構築には欠かせないスキャフォールディング機能について理解できたはずだ。
今回からは、ASP.NET MVCの中核ともいえるコントローラ部分について、よりつまびらかに見ていく。今回扱うのは、コントローラ(アクション・メソッド)の挙動を操作するためのActionResultオブジェクトについてである。
ActionResultオブジェクトとは
本連載第1回でも学んだように、アクション・メソッドは戻り値としてActionResultオブジェクト(またはその派生オブジェクト)を返すのが基本だ。つまり、ActionResultオブジェクトとは、アクションの結果を表すためのオブジェクトで、ASP.NET MVCでは、ActionResultオブジェクトの内容に応じて次の挙動を決定することになる。
ActionResultにはさまざまな派生オブジェクトが存在しているが、その中でも代表的なものはViewResultオブジェクト。アクション・メソッドの処理後に、指定されたビューを呼び出すためのActionResult派生オブジェクトだ。
これまでにも、アクション・メソッドの末尾で以下のような記述は頻々(ひんぴん)と見かけたと思う(以下、背景が緑色のコード表記はすべてVB用)。
Return View()
Return View("Result")
これまであまり明確に意識することはなかったが、実はViewメソッドとは、戻り値としてアクションの結果を表すViewResultオブジェクトを返すためのメソッドであったわけだ。
次のように、Viewメソッドを使わずに、直接にViewResultクラスをインスタンス化することもできるが、あえて冗長な記述を採用する意味はないだろう。
Return New ViewResult()
Return New ViewResult() With { _
.ViewName = "Result", .ViewData = ViewData}
さて、前置きが長くなったが、本稿ではViewResultオブジェクトに代表されるもろもろのActionResult派生オブジェクトと、その具体的な用例について、関連する事項とともに見ていくことにしたい。本稿で扱うActionResult派生オブジェクトは、次のとおりである。
クラス名 | 概要 | ヘルパー・メソッド |
---|---|---|
ViewResult | 指定されたビューを出力 | View |
PartialViewResult | 指定されたユーザー・コントロールを出力 | PartialView |
RedirectResult | 指定されたURLにリダイレクト | Redirect |
RedirectToRouteResult | 指定されたアクションにリダイレクト | RedirectToRoute RedirectToAction |
ContentResult | 指定された文字列を出力 | Content |
FilePathResult | 指定されたパスの内容をファイルとして出力 | File |
FileContentResult | byte配列の内容をファイルとして出力 | File |
FileStreamResult | ストリームの内容をファイルとして出力 | File |
JavaScriptResult | 指定されたコンテンツをJavaScriptスクリプトとして出力 | JavaScript |
JsonResult | 指定されたコンテンツをJSON(JavaScript Object Notation)として出力 | Json |
HttpUnauthorizedResult | 承認の失敗時にHTTP応答コード「401 Unauthorized」をセット | − |
EmptyResult | 何もしない | − |
表1 ASP.NET MVCで利用できる主なActionResult派生オブジェクト |
ビュー・スクリプトによるページの生成− ViewResultオブジェクト −
まずは、ビュー・スクリプト(通常はWebページを記述した.aspxファイル)を呼び出すためのViewResultオブジェクトから。
これは、ControllerクラスのViewメソッドを経由して呼び出すことができる。ViewResultオブジェクトについては、本稿冒頭はもちろん、前回までの記事でも繰り返し触れている内容なので、もはやいい尽くしてしまった感もあるが、ここでは、ここまでの内容で触れることのできなかった「ビュー・スクリプトを検索する順番」について補足しておくことにしよう。
以前、Viewメソッドの引数にビュー名を指定しなかった場合、デフォルトでは「/Views/コントローラ名/アクション名.aspx」が検索される、と述べた。では、対応するビュー・スクリプトが見つからなかった場合にはどうなるのだろうか。
実は、ASP.NET MVC*1はビュー・スクリプトを以下の順番で検索する。
- /Views/コントローラ名/アクション名.aspx
- /Views/コントローラ名/アクション名.ascx
- /Views/Shared/アクション名.aspx
- /Views/Shared/アクション名.ascx
*1 厳密には、デフォルトのビュー・エンジンであるWebFormViewEngineクラス(System.Web.Mvc名前空間)。
この規則は、Viewメソッドで、
View("Result")
Html.RenderPartialメソッドで、
Html.RenderPartial("DetailTemplate")
のように、ビュー名が明示的に指定された場合にも同様だ。その場合、アクション名をビュー名と読み替えていただければよい。
- /Views/コントローラ名/ビュー名.aspx
- /Views/コントローラ名/ビュー名.ascx
- /Views/Shared/ビュー名.aspx
- /Views/Shared/ビュー名.ascx
従って、例えば第2回のDetailTemplate.ascxをDetails.ascxとし、Details.aspxの内容を以下のように書き換えてしまうと、サンプルは正しく動作しない。
<% Html.RenderPartial("Details", Model) %>
この場合、コードとしては拡張子が「.ascx」の、
/Views/Book/Details.ascx
を呼び出すことを意図しているわけであるが、RenderPartialメソッドは先に、
/Views/Book/Details.aspx
を検索してしまう。このため、Details.aspxがDetails.aspxを呼び出す循環参照となってしまうのである。このような間違いは意外とよくありがちなので注意されたい。
なお、「/Views/Shared」フォルダは、名前のとおり、複数のコントローラから共通して利用するようなビュー・スクリプトを格納するためのフォルダである。主にマスタ・ページ(.masterファイル)やユーザー・コントロール(.ascxファイル)を配置することが多いが、そのほか、カスタム・エラーページのようにアプリケーション共通で呼び出すような.aspxファイルも「/Views/Shared」フォルダに配置することになるだろう(カスタム・エラーページについては次回解説の予定である)。
アクションの処理後、異なるアクションにリダイレクトする− RedirectToRouteResultオブジェクト −
あるアクションを処理した後、異なるアクションに処理を移したいことがあるだろう。例えば、第2回で紹介したBook/Createメソッドでは、書籍情報を登録した後、Book/Indexアクションに処理を遷移していた。このようなケースで、RedirectToRouteResultオブジェクトは利用できる(対応するヘルパー・メソッドはRedirectToAction)。
もっとも、Book/Createアクションの例であれば、以下のように書き換えてもよいではないかと思われるかもしれない。
Return RedirectToAction("Index")
Return Index()
これにより、一見すると、Book/Indexアクションが呼び出されているように見えるかもしれないが、これは不可である。というのも、実際にはこの時点でASP.NET MVCが認識しているアクションは、もともとリクエストされているBook/Createアクションであるからだ。従って、ビューも(期待する)Book/Index.aspxではなく、Book/Create.aspxが呼び出されてしまうのである。
この問題は、Book/Indexアクションを以下のように書き換えることで回避することも可能ではある。
Return View(books)
Return View("Index", books)
なるほど、こうすれば登録処理の後、正しくBook/Index.aspxの内容が表示される。しかし、実際に実行してみれば分かるように、この場合、ブラウザに表示されるアドレスは(「http://localhost:4419/Book/Index」ではなく)、
http://localhost:4419/Book/Create
のままであるのだ。利用者がこのアドレスをそのままブックマークしてしまうことは、SEO(Search Engine Optimization)/SMO(Social Media Optimization)の観点からも好ましくない。さらに、この状態で[F5]キーを押してページをリフレッシュしてしまうと、再度、登録処理が呼び出されてしまうという問題もある。
以上のことから、何かしらの処理後は、基本的にRedirectToRouteResultオブジェクトを利用するべきであると覚えておこう。
ちなみに、リダイレクト先が外部サイトである場合などは、(RedirectToRouteResultオブジェクトではなく)RedirectResultオブジェクトを利用するとよい。対応するヘルパー・メソッドはRedirectである。例えば、アクションの処理後に「http://www.wings.msn.to/」にリダイレクトしたいならば、以下のように記述すればよい。
Return Redirect("http://www.wings.msn.to/")
[参考]Controller.TempDataプロパティによる一時データの保存
ASP.NET MVC固有の機能として、一時的なデータの保存先としてController.TempDataプロパティが用意されている。
TempDateを用意することで、リダイレクト前のアクションと、リダイレクト後のアクションとで、データを共有することが可能になる。TempDataプロパティに関する詳細は、後日、「.NET TIPS:[ASP.NET MVC]リダイレクトの前後でデータを共有するには?」で紹介の予定である。
Copyright© Digital Advantage Corp. All Rights Reserved.