2016年11月25日金曜日

ASP.NET MVC 04_ルーティングの基礎

VisualStuidioCommunity2015/Fw4.5.2/C#


前回は、コントローラーとアクションメソッドを作成しました。

その際、
ASP.NET MVCでは「フロントコントローラ方式」で、リクエストを1カ所で受け取り、URLから個々のコントローラークラスに振り分けます。
コントローラークラスには複数のアクションメソッドが定義されていて、URLからどのアクションメソッドが実行されるかが決定します。
アクションメソッドではユーザーからのリクエストに応じた処理を行って、ビューを表示するなどのレスポンスを返します。
と書きました。

今回は、リクエストされたURLからどのようにコントローラーとアクションメソッドが呼び出されているのか見ていきます。
リクエストされたURLから呼び出すアクションを決定する仕組みのことをルーティングと言います。

ルート定義ファイル

ルーティングを行うためのルート定義はソリューションのApp_Startフォルダ/RouteConfig.csファイルに記載されています。

プロジェクトを作成するとデフォルトで以下の内容が書かれています。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Practice01_Begin
{
    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 }
            );
        }
    }
}
RouteConfigクラスのRegisterRoutesメソッドで、ルート定義を作成します。

16行目~20行目でリクエストURLが、どのコントローラーのどのアクションメソッドにマッピングされるかが定義されています。
routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

RouteCollectionクラスのMapRouteメソッドで、マッピングのルートを設定します。
MapRouteメソッドの引数
・nameはルートを識別するための名前です。一意になるように設定します。
・urlはマッピングを行うためのURLのパターンを設定します。
・defaultsはurlで指定したプレースホルダー({}で囲まれた部分)が省略された時のデフォルト値を指定します。

つまりルート名「default」の定義は
・URLが「コントローラー名/アクションメソッド名/アクションメソッドの引数」で構成されていて
・コントローラー名が指定されていなければ「Home」コントローラーを
・アクションメソッドが指定されていなければ「Index」アクションメソッドを
・アクションメソッドの引き数idはUrlParameter.Optionalで省略可能です。
ということになります。

以下のようなリクエストURLはすべて、HomeコントローラーのIndexアクションメソッドが呼ばれれます。
URLの大文字小文字は区別されません。
http://localhost:12345
http://localhost:12345/Home
http://localhost:12345/Home/Index
http://localhost:12345/Home/Index/xxx


ルート定義をアプリケーションに適用する

RouteConfigクラスのRegisterRoutesメソッドで、ルート定義を作成しただけではルーティングは行われません。
あたりまえですけど、RegisterRoutesメソッドではメソッドの処理を書いただけで、メソッドを呼び出さなければその処理は実行されません。
「Config」と付いていると、定義を書くだけでアプリケーションに適用されそうな気がしてしまうのは私だけでしょうか・・・

アプリケーションでルーティングを行うためには、Global.asaxファイル内の Application_Startイベントで、RouteConfigクラスのRegisterRoutesメソッドを呼び出します。
Global.asaxはグローバルアプリケーションファイルと呼ばれ、アプリケーションレベルでのイベントを処理するためのクラスです。
アプリケーションが起動すると、Application_Startイベントが発生します。
このApplication_Startイベント内でRouoteConfigクラスのRegisterRoutesメソッドを呼び出すことで、ルーティングがアプリケーションに適用されます。


プロジェクトを作成すると、Global.asaxファイルにはデフォルトで以下の内容が書かれています。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace Practice01_Begin
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}
17行目でRouteConfigクラスのRegisterRoutesメソッドを呼び出しています。

ルートを定義してみる

新しいルートを定義してみます。

デフォルトルートより前にGreetingルートを追加してみました。
Greetingルートでは、URL「http://localhost:12345/Greeting/Show」を前回作成したHelloコントローラのShowHelloMessageアクションメソッドにマップします。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Practice01_Begin
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            //Greetingルート
            routes.MapRoute(
                name: "Greeting",
                url: "Greeting/Show",
                defaults: new { controller = "Hello", action = "ShowHelloMessage" }
            );
            //デフォルトルート
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );

            
        }
    }
}
MapRouteメソッドの引数 url にコントローラー名とアクション名が含まれない場合、引数 default にコントローラ名とアクション名が必須になります。
デバッグ実行し、アドレスバーに「http://localhost:12345/Greeting/Show」と入力します。
前回同様に「Hello World」と表示されます。

次に、GreetingルートをDefaultルートの後ろに定義してみます。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Practice01_Begin
{
    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 }
            );
            //Greetingルート
            routes.MapRoute(
                name: "Greeting",
                url: "Greeting/Show",
                defaults: new { controller = "Hello", action = "ShowHelloMessage" }
            );

        }
    }
}
先ほどと同じようにデバッグ実行し、アドレスバーに「http://localhost:12345/Greeting/Show」と入力します。
今度は以下のようなエラー画面が表示されました。

URL 「http://localhost:12345/Greeting/Show」 はDefaultルートが適用され、Greetingがコントロール名、Showがアクションメソッド名としてルーティングされるんですね。

ルートを定義する順番には注意が必要です。

0 件のコメント: