ASP.NET ルーティングの仕組み
ASP.NET ルーティングはどのような仕組みで実現されているのでしょうか。
これを理解するには、まずASP.NETの仕組みを理解しておく必要があります。
上記ページのうち、1から3の部分を特におさえておいてください。
この部分を大雑把にまとめると、
- HttpContextがリクエストを受け取ってからレスポンスを返すまで一種のグローバルオブジェクトとして存在している
- HttpApplicationが様々なイベントを発生させるタイミングでIHttpModuleが各種処理を実行することができる
- 実際に実行されるのはHttpContextのHandlerプロパティに設定されているIHttpHandler(のProcessRequestメソッド)である
ということをまず頭においてください。
ASP.NET ルーティングを利用するにはweb.configにUrlRoutingModuleを登録します。
Moduleは登録されると、すべてのリクエストに対して実行されます。
このUrlRoutingModuleがブラウザからのリクエストを調べて、登録されているルートに合致するかどうかを判断します。
このとき、リクエストされているURLが現在存在しているファイル(aspxなど)を直接指定している場合は、ルートとの合致の調査は行われず(デフォルトの動作)、指定されているファイルがそのまま呼び出されます。
それ以外の場合で登録されているルートがあったら、そのルートに対して設定されているIRouteHandlerのGetHttpHandlerメソッドが呼び出されます。
IRouteHandlerの実装例やその登録の仕方については下記のページを参考にしてください。
GetHttpHandlerメソッドはIHttpHandlerを返すことが求められています。
で、ここで返されたIHttpHandlerがHttpContextのHandlerプロパティに設定されます。
そして、このHandlerプロパティに設定されているIHttpHandlerのProcessRequestが実行されることになります。
要するにとっても簡単に言うと、UrlRoutingModuleが処理を横取りして、実行されるページ(のインスタンス)を置き換えてしまう、というのがASP.NET ルーティングが行っている動作です。
また、その中でどんなページに置き換えるかを指定するためにIRouteHandlerの実装が必要、ということになります。
ちょっと気をつけないといけないのは、IHttpHandlerのインスタンスのレベルで置き換えが行われている、ということですね。
リクエストの処理の中で内部的にリクエストされたURLを書き換えてしまう(RewritePath)のと異なり、URLの変更は行われないので、ポストバック先はもともとリクエストされたURLになりますし、クエリ文字列としてURLに含まれたデータを取り出すことはできない、ということになります。
さて、ここまででASP.NET ルーティングの仕組みとその実装方法(上記ページ参照)を説明しました。
あと、aspxページ内でルーティングに合わせたURLを生成する方法については、下記を参照していただければよいと思います。
これで、実際のASP.NETアプリケーションの中でASP.NETルーティングを利用するための準備は整ったのではないかと思います。
現実にどのようなルーティングをアプリケーションで使っていくのがよいか、これからいろいろ考えてみます。
ASP.NET ルーティングを実装する
.NET Framework 3.5 SP1でASP.NETにルーティングという機能が追加されました。
ASP.NET ルーティングがどういうものか、という話については次のページをみてもらうのがよいと思います。
上記ページの中にサンプルとしてCategoryRouteHandlerを使った例がありますが、このCategoryRouteHandler、どこを探しても存在していません。
そのあたりの疑問を解決するには次のページを見てください。
Web.Configの設定のあとに、「ハンドラを作成するには」という項目があります。
ここに記述されていますが、実はIRouteHandlerインターフェイスを実装するクラスを自分で実装しない限りルーティングは利用できない、というのが実情です。
上記ページには単純なIRouteHandlerの実装例がでていますが、もう少し柔軟に運用できるルーティングハンドラとURLに含まれるデータを取り出す方法を実装してみました。
作成したソースは以下のとおりです。
using System.Web;
using System.Web.UI;
using System.Web.Compilation;
using System.Web.Routing;
using System.Linq;
public class SimpleRouteHandler : IRouteHandler
{
public string VirtualPath { get; set; }
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
string vPath = VirtualPath;
var keys = from s in vPath.Split(‘/’)
where s.Contains(‘{‘) && s.Contains(‘}’)
select s.Remove(s.IndexOf(‘}’)).Substring(s.IndexOf(‘{‘) + 1);
foreach (string key in keys)
{
vPath = vPath.Replace("{" + key + "}", requestContext.RouteData.GetRequiredString(key));
}
return BuildManager.CreateInstanceFromVirtualPath(vPath, typeof(Page)) as IHttpHandler;
}
}
public partial class SimpleRouteValue
{
public static string GetRequiredString(string valueName)
{
RouteData routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current));
return routeData != null ? routeData.GetRequiredString(valueName) : string.Empty;
}
}
SimpleRouteHandlerクラスがIRouteHandlerインターフェイスを実装したハンドラです。
ルートの定義に対して固定のページを指定するだけでなく、ページの指定時にもルート定義と同様の記述を可能にしています。
※ルート定義とページ指定の例
ルート定義 | ページ指定 | アクセスURL | 実行されるページ |
{action}/{id} | "~/Update.aspx" | http://localhost/site1/Update/4 | "~/Update.aspx" |
{action}/{id} | "~/{action}.aspx" | http://localhost/site1/Update/4 http://localhost/site1/Delete/4 |
"~/Update.aspx" "~/Delete.aspx" |
SimpleRouteValueクラスはURLに含まれる値を取り出すために利用します。
上記の例でいうと、Update.aspxやDelete.aspxではidの値を直接取り出すことができません。このあたりはURLの書き換えを行った場合と異なっているところです。
このため、SimpleRouteValueクラスを利用してidの値を取り出せるようにしました。
この実装を利用するためには、まず「方法 : Web フォームでルーティングを使用する」のページを参考にWeb.Configの設定を行ってください。
IIS6.0の場合、IIS7.0の場合、といった場合わけした記述がありますが、すべての設定をしておけば必要ない部分は読み飛ばされるだけなので、あまり気にせず設定してください。
次に、Global.asaxに下記のように記述します。
void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add(new Route("{action}/{id}", new SimpleRouteHandler() { VirtualPath = "~/{action}.aspx" }));
}
そして、Update.aspxページを追加し、その中にLabelコントロールを置いて、下記のプログラムを記述します。
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = SimpleRouteValue.GetRequiredString("id");
}
この状態で、"~/Update/6" のようなURLにアクセスすると、Update.aspxページが実行され、idの値を取り出せていることが確認できると思います。
ルートの規定値や制約も利用できますから試してもらうとどのような動きをするのかわかると思います。
また、Update.aspxページにボタンを追加し、クリック時の処理を記述して実行してみると、ポストバック時にも元のURLにアクセスすることが確認できます。この点もURLの書き換えとは異なっている部分です。URLの書き換えだとaspxページに手を入れないとポストバック時に書き換えられたURLが表示されてしまいます。
なお、IIS6上でASP.NETルーティングで上記のような拡張子のないURLを利用するには、ワイルドカードアプリケーションマッピングを利用してすべてのリクエストがASP.NETに渡されるように設定する必要があります。
URLの表記をできるだけきれいにしたい、と考えている人にとってはASP.NETルーティングは十分検討に値する機能だと思います。
どのような仕組みでこのルーティングが実現されているかについては別途まとめようと思います。