.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引数は、あくまでコントローラ・クラスの検索先を定義するのみで、検索順序までを制約するものではない、ということだ。注意されたい。End of Article

利用可能バージョン:.NET Framework 3.5
利用可能バージョン:.NET Framework 4
カテゴリ:ASP.NET MVC 処理対象:ルーティング

この記事と関連性の高い別の.NET TIPS
[ASP.NET MVC]ルート定義を追加するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間