|
.NET TIPS
[ASP.NET MVC]コントローラ・クラスの検索先を制限するには?[3.5、4以降、C#、VB]
山田 祥寛
2010/08/12 |
|
|
ASP.NET MVCでコントローラ・クラスを定義するのは、さほど難しいことではない。コントローラ・クラスであることの条件は「Controllerクラスを継承していること」だけである*1。「ASP.NET MVCフレームワーク 基本のキ」では、コントローラ・クラスは「アプリケーション・ルート直下の/Controllersフォルダに配置すること」としているが、実はこれすらも必須ではない。ASP.NET MVCは、Controller派生クラスをあらゆる名前空間(現在のプロジェクトとその参照先のアセンブリ)から検索するため、特に配置先のフォルダや名前空間を制限していないのだ。
*1 正確には、IControllerインターフェイスを実装したpublicクラスであること。しかし、実際にはIControllerインターフェイスを直接実装する機会は、実装の手間暇を考えても多くはないはずだ。
|
これは一見すると便利なことのように思えるが、時として、予期せぬ名前の衝突を引き起こす原因にもなる。例えば、複数の名前空間(以下のサンプルではMvcApp.Controllers名前空間とMvcApp.Controllers2名前空間)に対して、以下のようなSampleコントローラを定義してみよう。中身はごくシンプルで、現在の名前空間をテキスト表示するだけのコントローラである。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace MvcApp.Controllers {
// Sample/Indexアクションを定義
public class SampleController : Controller {
public ActionResult Index() {
return Content("Controllers名前空間");
}
}
}
|
Namespace Controllers
' Sample/Indexアクションを定義
Public Class SampleController
Inherits System.Web.Mvc.Controller
Function Index() As ActionResult
Return Content("Controllers名前空間")
End Function
End Class
End Namespace
|
|
MvcApp.Controllers名前空間に属するSampleコントローラ(上:SampleController.cs、下:SampleController.vb) |
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace MvcApp.Controllers2 {
// Sample/Indexアクションを定義
public class SampleController : Controller {
public ActionResult Index() {
return Content("Controllers2名前空間");
}
}
}
|
Namespace Controllers2
' Sample/Indexアクションを定義
Public Class SampleController
Inherits System.Web.Mvc.Controller
Function Index() As ActionResult
Return Content("Controllers2名前空間")
End Function
End Class
End Namespace
|
|
MvcApp.Controllers2名前空間に属するSampleコントローラ(上:SampleController2.cs、下:SampleController2.vb) |
この状態で、「http://localhost:8080/Sample/Index」にアクセスするとどうだろう。以下のようなInvalidOperationException例外が発生することになる。
|
InvalidOperationException例外が発生 |
MvcApp.Controllers名前空間とMvcApp.Controllers2名前空間とでSampleコントローラの名前が重複して存在するため、いずれのコントローラを実行してよいものか、判定できないのだ*2。
*2 重複はコントローラ単位で認識されるので、双方のコントローラでアクション・メソッドの名前が重複していなくとも、結果は変わらない。 |
このようなケースでは、ルート定義(MapRouteメソッド)の第5引数に、以下のようなコードを追加してみよう(追記部分は太字で記述している)。
routes.MapRoute(
"Default", // ルート名
"{controller}/{action}/{id}", // URIパターン
new { controller = "Home", action = "Index", id = "" }, // デフォルト値
new {}, // 制約条件
new[] { "MvcAppCs.Controllers" } // 検索先の名前空間
);
|
routes.MapRoute( _
"Default", _ ' ルート名
"{controller}/{action}/{id}", _ ' URIパターン
New With {.controller = "Home", .action = "Index", .id = ""}, _ ' デフォルト値
Nothing, _ ' 制約条件
New String() {"MvcApp.Controllers"} _ ' 検索先の名前空間
)
|
|
ルーティング先の名前空間を制限する例(上:Global.asax.cs、下:Global.asax.vb) |
MapRouteメソッドの第5引数には、コントローラ・クラスの検索先(名前空間)を文字列配列として指定できる。
試しに、この状態でもう一度「http://localhost:8080/Sample/Index」にアクセスしてみよう。今度は、確かに「Controllers名前空間」と表示され、MvcApp.Controllers名前空間のSampleコントローラが呼び出されていることが確認できる。
ちなみに、リストの太字部分を以下のように書き換えるとどうだろう(上:C#、下:VB)。
new[] { "MvcAppCs.Controllers", "MvcAppCs.Controllers2" } |
New String() {"MvcApp.Controllers", "MvcApp.Controllers2"} _ |
|
MvcApp.Controllers名前空間、MvcApp.Controllers2名前空間の順序でコントローラを検索してくれることを期待するかもしれないが、結果はやはりInvalidOperationException例外が発生する。要は、MapRouteメソッドの第5引数は、あくまでコントローラ・クラスの検索先を定義するのみで、検索順序までを制約するものではない、ということだ。注意されたい。
利用可能バージョン:.NET Framework 3.5
利用可能バージョン:.NET Framework 4
カテゴリ:ASP.NET MVC 処理対象:ルーティング |
|
generated by
|
|
Insider.NET 記事ランキング
本日
月間