|   | 
 
|  
 .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 記事ランキング
		
		
			本日
			月間