アーキテクチャをスマートに。

株式会社ネオジニア代表。ITアーキテクトとしてのお仕事や考えていることなどをたまに綴っています。(記事の内容は個人の見解に基づくものであり、所属組織を代表するものではありません)

ASP.NET MVC 4 ことはじめ(3)ルーティング

ルーティングについて

アクセスされたURLに対して、どのコントローラを起動するか割り当てることを「ルーティング」と呼びます。ルーティング定義は、Global.asax の Application_Start() で設定します。
ASP.NET MVC 3 までは、ルート定義をカスタマイズする際に直接 Global.asax 内に書いていましたが、ASP.NET MVC 4 からは App_Start/RouteConfig.cs に書くことになっています。自動生成されたソースコードがすでにそうなっています。
Global.asax を開いてみてください。Application_Start() 内で RouteConfig.RegisterRoutes() を呼び出しています。
他にも、BundleConfig, FilterConfig, WebApiConfig など、Application_Start() 内で呼び出すコンフィグは App_Start フォルダにまとめられています。

ルーティング定義

では、自動生成されたソースコードのルーティング定義を見てみましょう。

App_Start/RouteConfig.cs

namespace HelloWorld1
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");    // オマジナイ

            routes.MapRoute(
                name: "Default",                                // 定義名
                url: "{controller}/{action}/{id}",              // ルーティング情報
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }   // デフォルト
            );
        }
    }
}

IgnoreRoute() はリソースデータに直接アクセスされない為のオマジナイです。
MapRoute() でルート定義をマッピングしていますね。

name: "Default"

これは単にルート定義の名前です。

url: "{controller}/{action}/{id}"

これはURLの構造とマッピングを表しています。
例えば、 http://localhost:53280/Abc/Def/12 というリクエストURLだった場合、AbcController クラスの Def() メソッドが呼び出され、引数 id に 12 が渡される、という具合です。
このとき、URLの大文字小文字は関係ありません。
http://localhost:53280/aBc/deF/12 としても呼び出されるコントローラメソッドはやはり AbcController.Def() です。

最後に、

defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

ですが、これはデフォルトの定義を表していて、リクエストURLで明示されなかった場合にどの値とみなすか、といった解釈でよいと思います。トップURLへのアクセスで HomeController.Index() が呼び出されるのはこのデフォルト定義があるためです。パラメータ「id」はOptional、つまり省略可能であることを表しています。

したがって、このルーティング設定では以下のような認識となります。

リクエストURL controller action id
http://localhost:53280/Abc/Def/12 Abc Def 12
http://localhost:53280/Abc/Def Abc Def null
http://localhost:53280/Abc Abc Index null
http://localhost:53280/ Home Index null

実際に AbcController を作成し、Defメソッドを作って試してみると、動きがよくわかると思います。

Controllers/AbcController.cs

namespace HelloWorld1.Controllers
{
    public class AbcController : Controller
    {
        //
        // GET: /Abc/

        public ActionResult Index()
        {
            return View();
        }

        //
        // GET: /Abc/Def/id

        public ActionResult Def(string id)
        {
            ViewData["msg"] = "Defメソッドです。id は[" + id + "]です。";
            return View();
        }
    }
}

ビューは Index と Def の2つを作っておきましょう。(先に Views/Abc フォルダを作る必要があります)

Views/Abc/Index.cshtml

@{
    ViewBag.Title = "Index";
}

<h2>Abc Index</h2>

<p>
    @ViewData["msg"]
</p>

Views/Abc/Def.cshtml

@{
    ViewBag.Title = "Def";
}

<h2>Abc Def</h2>

<p>
    @ViewData["msg"]
</p>

では実行してみましょう。
ブラウザのURLを以下のように直接打ち変えてみて、どのような動きをするか試してみて下さい。

http://localhost:53280/Abc
http://localhost:53280/Abc/Def
http://localhost:53280/Abc/Def/12
http://localhost:53280/aBc/dEF/X9876

ちなみに Def() メソッド内で View("Index") とすれば、Def.cshtml を作らなくてもOKです。

パラメータの割り当ては「モデルバインダ」がやってくれる

さて Def() メソッドの引数「id」ですが、URLで与えられたパラメータが変換されて渡されます。型とかあまり深く考えなくても自動的に変換してくれます。

例えば、

public ActionResult Def(string id)

のところは、

public ActionResult Def(int? id)

としてもよいです。
パラメータを整数値として受け取ることができます。int? としているのは、パラメータを省略可能だからです。

URLのクエリ文字列だけでなく、フォームパラメータをメソッド引数に割り当てるようなことも可能です。これは ASP.NET MVC の強力なモデルバインダの機能で実現されています。
ファイルアップロードとかも対応してます。
詳しくは「モデルバインダ」でググるとたくさん情報が得られますよ。