.NET TIPS

[ASP.NET MVC]ルート定義を追加するには?[3.5、4、C#、VB]

山田 祥寛
2010/07/08

 ルーティングとは、リクエスト時のURIに応じて処理の受け渡し先(コントローラ)を決定すること、または、その仕組みのことだ。ASP.NET MVCでは、デフォルトでルーティングが有効になっており、最初のうちはルーティングを利用していくことを意識すらしないかもしれない。そうした意味で、ルーティングとはASP.NET MVCの挙動の根幹を支える仕組みといってもよいだろう*1

*1 だからといって、ルーティングがASP.NET MVC固有の仕組みというわけではない。ASP.NET本体でもルーティングを利用することは可能である。

 本稿では、このルーティングを定義するための基本的な方法(構文)について解説する。

●ルート定義の基本

 手始めに、ASP.NET MVCデフォルトで用意されているルーティング・ルール(ルート)を確認してみよう。ルートを定義しているのは、Global.asaxの役割である。

// ルート定義を登録するメソッド
public static void RegisterRoutes(RouteCollection routes) {
  ……中略……
  // Defaultルートを定義
  routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id =
      UrlParameter.Optional }
  );
}

// アプリケーション起動時にルート定義を登録
protected void Application_Start() {
  ……中略……
  RegisterRoutes(RouteTable.Routes);
}
' ルート定義を登録するメソッド
Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
  ……中略……
  ' Defaultルートを定義
  routes.MapRoute( _
    "Default", _
    "{controller}/{action}/{id}", _
    New With { .controller = "Home", _
               .action = "Index", .id = UrlParameter.Optional } _
  )
End Sub

' アプリケーション起動時にルート定義を登録
Sub Application_Start()
  ……中略……
  RegisterRoutes(RouteTable.Routes)
End Sub
デフォルトで用意されているルート定義(上:Global.asax.cs、下:Global.asax.vb)

 RegisterRoutesメソッドはアプリケーション起動(Startイベント・ハンドラ)のタイミングで呼び出されるメソッドで、デフォルトのルート(名前はDefault)を追加している。

 ルートを追加するには、ルートの集合を表すRouteCollectionオブジェクトからMapRouteメソッドを呼び出すだけだ。MapRouteメソッドの構文は、次のとおりである。

MapRoute(String name, String url [,Object defaults])
MapRouteメソッドの構文
name:ルート名。
url:URIパターン。
defaults:初期値。

 引数urlは、ルーティングに際して、実際にマッチさせるURIパターンを表すものだ。例えば、Defaultルートでは、以下のようなパターンが定義されている。

{controller}/{action}/{id}

 {名前}の部分は変数のプレイスホルダで、{controller}はコントローラ名、{action}はアクション名、{id}はアクション・メソッドに引き渡される任意のパラメータ(ユーザー・パラメータ)を、それぞれ表す。

 {controller}/{action}はあらかじめ決められた名前であるので、勝手に変更することはできないが、{id}は必要に応じて適宜変更しても構わない。

 これら変数のデフォルト値を指定しているのが、引数defaultsだ。Defaultルートでは、

new { controller = "Home", action = "Index", id = UrlParameter.Optional }
New With { .controller = "Home", .action = "Index", .id = UrlParameter.Optional } _

のように記述しているので、

controller = Home
action = Index
id = 任意(ブランクも可)

であると見なされるわけだ。つまり、この設定においては、それぞれ以下のURLでは以下のように認識されることになる。

リクエストURL controller action id
http://localhost:8080/Book/Details/12345 Book Details 12345
http://localhost:8080/Book/Create Book Create (ブランク)
http://localhost:8080/Book Book Index (ブランク)
http://localhost:8080/ Home Index (ブランク)
リクエストURLとパラメータにセットされる値

●アプリケーション固有のルート定義を追加する

 ルート定義の基本が理解できたところで、具体的な例を挙げながら自作のルート定義を追加してみよう。なお、ルート経由で取得したパラメータ値を確認するために、あらかじめ以下のようなRoute/Indexアクションを定義しておくものとする。

public ActionResult Index() {
  // ルート経由で渡されたパラメータを「キー名:値」の形式で列挙
  foreach (var param in RouteData.Values) {
    Response.Write(String.Format("<p>{0}:{1}</p>",
      param.Key, param.Value));
  }
  // アクションで出力そのものを行っているので、
  //処理後は何もしない(*2
  return new EmptyResult();
}
Function Index() As ActionResult
  ' ルート経由で渡されたパラメータを「キー名:値」の形式で列挙
  For Each param In RouteData.Values
    Response.Write(String.Format("<p>{0}:{1}</p>", _
      param.Key, param.Value))
  Next
  ' アクションで出力そのものを行っているので、
  ' 処理後は何もしない(*2
  Return New EmptyResult()
End Function
ルート・パラメータを列挙するためのアクション・メソッド(上:RouteController.cs、下:RouteController.vb)

*2 ここではサンプルという便宜上、アクション・メソッドで直接に出力を生成しているが、本来、コントローラでは出力を担当するべきでない。

 ルート・パラメータは、RouteDataプロパティにアクセスすることで取得できる。ここでは、そのValuesプロパティから個別のパラメータを取り出し、順に出力しているわけだ。ルート・パラメータの扱いについては、「ASP.NET MVCフレームワーク 基本のキ」も併せてご参照いただきたい。

(1)複数のパラメータを受け取るルート定義

 前述したように、パラメータは自由に設定して構わない。例えば、以下のように複数のパラメータを受け取ることも可能だ。

routes.MapRoute(
  "Multi",    // ルート名
  "{controller}/{action}/{first}/{second}"    // URIパターン
);
routes.MapRoute( _
  "Multi", _  ' ルート名
  "{controller}/{action}/{first}/{second}" _  ' URIパターン
)
複数のパラメータを受け取るMultiルートを定義するコード(上:Global.asax.cs、下:Global.asax.vb)

 ここではfirst、secondと2つのパラメータを定義しているが、もちろん、必要に応じて3個以上のパラメータを定義しても構わないし、そもそも{controller}、{action}が先頭にくる必要もない。例えば、

{first}/{controller}/{action}/{second}

のようなパターンも妥当なURIパターンである。

 Multiルートではデフォルト値を定義していない点にも注目だ。前述したように、デフォルト値が定義されているパラメータは省略可能となる。つまり、デフォルト値が定義されていないということは、すべてのパラメータは省略「できない」ということである。

 このルートに対して、次のアドレスでアクセスした場合の結果は、以下のとおりである。

http://localhost:8080/Route/Index/12345/xyz
controller:Route
action:Index
first:12345
second:xyz
上記のアドレスでアクセスした場合の結果

(2){controller}/{action}パラメータを持たないルート定義

 そもそもURIパターンに{controller}、{action}パラメータを含まないルートを定義しても構わない。

routes.MapRoute(
  "Article",  // ルート名
  "Article/{day}/{month}/{year}",    // URIパターン
  new {
    controller = "Route",  // コントローラ名
    action = "Index",      // アクション名
    day = DateTime.Now.Day,      // 日
    month = DateTime.Now.Month,  // 月
    year = DateTime.Now.Year      // 年
  }
);
routes.MapRoute( _
  "Article", _  ' ルート名
  "Article/{day}/{month}/{year}", _  ’URIパターン
  New With { _
    .controller = "Route", _      ' コントローラ名
    .action = "Index", _          ' アクション名
    .day = DateTime.Now.Day, _      ' 日
    .month = DateTime.Now.Month, _  ' 月
    .year = DateTime.Now.Year _     ' 年
  } _
)
URIパターンに{controller}、{action}を含まないArticleルートを定義するコード(上:Global.asax.cs、下:Global.asax.vb)

 URIパターンに{controller}、{action}を含まない場合、引数defaultsによる{controller}、{action}のデフォルト値の設定は必須となる(さもないと、処理を委譲すべきコントローラ/アクション名が特定できないからだ)。

 また、ここではデフォルト値にリテラルではなく、式を指定している点にも注目だ(リストの太字部分)。これによって、{year}/{month}/{day}パラメータが省略された場合、それぞれ現在の年月日がセットされることになる。

 以下に、リクエストURLとパラメータ値の関係をまとめておく。

リクエストURL controller action day month year
/Article/25/06/2009 Route Index 25 06 2009
/Article/25/06 Route Index 25 06 2010
/Article/25 Route Index 25 2 2010
/Article Route Index 24 2 2010
リクエストURLとパラメータにセットされる値(今日が2010/02/24の場合)

(3)パラメータの区切り文字を「-」に

 パラメータの区切り文字は何も「/」である必要はない。例えば、以下は(2)のURIパターンを「-」区切りで書き換えたものである(書き換え部分は太字で表している)。

routes.MapRoute(
  "Article",    // ルート名
  "Article/{day}-{month}-{year}.html",    // URIパターン
  new {
    controller = "Route",      // コントローラ名
    action = "Index"           // アクション名
  }
);
routes.MapRoute( _
  "Article", _  ' ルート名
  "Article/{day}-{month}-{year}.html", _  ' URIパターン
  New With { _
    .controller = "Route", _   ' コントローラ名
    .action = "Index" _        ' アクション名
  } _
)
パラメータを「-」以外で区切った場合のコード(上:Global.asax.cs、下:Global.asax.vb)

 確かに、

http://localhost:8080/Article/25-06-2009.html

のようなアドレスでアクセスできることを確認しておこう。もちろん、区切り文字の「-」は「.」(ピリオド)でも、それどころか「X」のようなアルファベットでも構わない。ただし、アルファベットや数値を区切り文字として利用することは、マッチするURLを分かりにくくする原因にだけでなく、思わぬURLがマッチしてしまう原因でもあるので、原則として避けるべきだ。通常は、パラメータの区切り文字は「/」「-」「_」「.」あたりに止めておくのが望ましいだろう。

 また、パラメータの間にそもそも区切り文字が入らない、

"Article/{day}{month}{year}.html",

のようなパターンは認められない。

(4)任意の数のパラメータを渡す場合

 特殊なパラメータの表記として{*名前}のように記述することもできる。

routes.MapRoute(
  "Many",            // ルート名
  "Many/{*param}",   // URIパターン
  new {
    controller = "Route",    // コントローラ名
    action = "Index"         // アクション名
  }
);
routes.MapRoute( _
  "Many", _            ' ルート名
  "Many/{*param}", _   ' URIパターン
  New With { _
    .controller = "Route", _     ' コントローラ名
    .action = "Index" _          ' アクション名
  } _
)
複数のパラメータを受け取るMultiルートを定義するコード(上:Global.asax.cs、下:Global.asax.vb)

 {*名前}は、以降のすべての値をそのパラメータに吸収するという意味である。例えば、このルートに対して、次のアドレスでアクセスした場合の結果は、以下のとおりである。

http://localhost:8080/Many/12345/67890/XYZ
param:12345/67890/XYZ
controller:Route
action:Index
Multiルートの定義に対して上記のアドレスでアクセスした場合の結果

 「Many/〜」以降のすべての値がparamにセットされていることが確認できるだろう。

 ちなみに、URIパターンを「Many/{param}」のようにアスタリスク(*)抜きにした場合には「/Many/12345」にはマッチするが、「/Many/12345/67890」「/Many/12345/67890/XYZ」などにはマッチしなくなる。

 {*名前}のパターンは、不特定多数のパラメータを受け取りたい場合(あらかじめパラメータの数が特定できない場合)に利用できるだろう。

 なお、アスタリスク付きのパラメータは、その性質上、URIパターンの末尾でしか利用できないので、注意されたい(アスタリスクがすべて吸収してしまうため、以降のパラメータが値を受け取ることは絶対にないためだ)。End of Article

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

この記事と関連性の高い別の.NET TIPS
[ASP.NET MVC]ルート・パラメータに制約条件を追加するには?
[ASP.NET MVC]特定のルートを無効化するには?
[ASP.NET MVC]ルート・パラメータに妥当な日付が渡されているかを判定するには?
[ASP.NET MVC]有効期限のあるルーティング規則を定義するには?
[ASP.NET MVC]特定のHTTPメソッドにマッチするルートを定義するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム 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 記事ランキング

本日 月間