デベロッパー

デベロッパー

ASP.NET 4.0におけるURLルーティング

Scott Mitchell
2010年4月20日 / 10:00
 
 

はじめに

 .NET Framework 3.5 SP1では、ASP.NETルーティングが導入され、リソースのURLをWebサーバ上の物理的なファイルから切り離すことが可能になりました。ASP.NETルーティングにより、開発者は、ルートパターンをコンテンツ生成クラスにマップするルーティングルールを定義できます。例えば、Categories/<カテゴリ名>というURLを、<カテゴリ名>を受け取ってそのカテゴリの商品一覧HTMLを生成するクラスにマップできます。このマッピングにより、ユーザーはwww.yoursite.com/Categories/BeveragesというURLを訪問することで、「Beverages(飲料)」のカテゴリにある商品を参照できるようになります。

 .NET 3.5 SP1では、ASP.NETルーティングは主にASP.NET MVCアプリケーション向けに設計されていました。記事「Using ASP.NET Routing Without ASP.NET MVC」で述べたように、ASP.NETルーティングをWeb Formsアプリケーションに実装することも可能です。しかし、Web FormsアプリケーションでのASP.NETルーティングの実装には、やや肉体労働的な作業が必要になります。Web Formsでは通常、ルーティングパターンを実際のASP.NETページにマップしたいと考えます。そのためには、ルートハンドラクラスを作成する必要があります。このクラスは、ルーティングURLが要求された場合に呼び出され、適切なASP.NETページへとその要求を転送します。例えば、ルート(Categories/<カテゴリ名>など)を物理的ファイル(ShowProductsByCategory.aspxなど)にマップするには、次の3つの処理が必要になります。

  1. Global.asaxにおいてマッピングを定義する
  2.  これによって、ルートパターンをルートハンドラクラスにマップします。

  3. ルートハンドラクラスを作成する
  4.  このクラスは、URLを解析し、ルートパラメータがあれば、それをターゲットページからアクセス可能なロケーション(HttpContext.Itemsなど)に保存し、要求されたルートを処理するターゲットページまたはHTTPハンドラのインスタンスを返します。

  5. ターゲットページのコードを記述する
  6.  ルートパラメータを取得し、それに基づいてコンテンツをレンダリングするコードを記述します。

 以上、読むだけでも大変だったでしょうから(書いた筆者も疲れました)、Web FormsアプリケーションでのASP.NETルーティングの実装が必ずしも単純明快な作業ではないことがお分かりいただけたと思います。

 幸い、ASP.NET 4.0では、上述の複雑さを隠蔽することのできる、いくつかのクラスとヘルパーメソッドが追加され、Web FormアプリケーションでのASP.NETルーティングが大幅に簡素化されました。ASP.NET 4.0では、より簡単にルーティングルールを定義することができ、特別なルートハンドラクラスを作成する必要はありません。本稿では、これらの拡張点について解説したいと思います。

ASP.NET 4.0の現在のステータスとリリース予定
 本稿執筆時点で、ASP.NET 4.0はベータ版が提供されています。.NET Framework 4.0とVisual Studio 2010 Beta 2をダウンロードするか、ASP.NET 4.0が正式にリリースされるまでお待ちください。現時点でASP.NET 4.0の正式版は、2010年4月にリリース予定です。

ASP.NETルーティングの概要

 ASP.NETルーティングでは、URLをWebページのファイル名から完全に切り離し、簡潔で分かりやすい「SEO(検索エンジン最適化)フレンドリなURL」の作成を可能とします。WebアプリケーションでASP.NETルーティングを使用する利点については、筆者の以前の記事「Using ASP.NET Routing Without ASP.NET MVC」の「The Case for ASP.NET Routing」のセクションを参照ください。その中で数段落を割いてASP.NETルーティングの利点について詳説しています。

 簡単に言えば、開発者はASP.NETルーティングにより、Categories/<カテゴリ名>といったルートパターンを、その要求を処理するクラスにマップする「ルーティングルール」を定義できます。これらのルーティングルールは、アプリケーション起動時に、Global.asaxのApplication_Startイベントハンドラにおいて定義されます。Web Formsアプリケーションでは、対象のコンテンツを生成するASP.NETページはおそらく既に存在するため、ここで必要な処理は、ルートパターンをASP.NETページにマップするルーティングルールを定義し、ルートパラメータ(<カテゴリ名>など)があればそれをそのASP.NETページに引き渡すことだけになります。ASP.NET 3.5 SP1のASP.NETルーティングでは、ルーティングパターンをASP.NETページに直接マップする方法がありませんでした。そのために、入力要求に関する情報を受け取り、要求を処理するHTTPハンドラを返す、ルートハンドラクラスを作成する必要がありました。Web Formsアプリケーションにおけるルートハンドラクラスの処理は通常、以下のステップからなります。

  1. 必要に応じてURLを解析します。通常は、特定のルーティングパラメータを調べて、その値によって処理を決定します。
  2. URLの中に、この要求を処理するASP.NETページまたはHTTPハンドラへと引き渡す必要のあるルーティングパラメータがあれば、取り出します。ここでは要するに、要求されたコンテンツを実際に生成するASP.NETページが、<カテゴリ名>などのルーティングパラメータの値を参照できるようにすることが必要です。このための手段として、HttpContext.Itemsコレクションにその情報を格納するという方法があります。HttpContext.Itemsコレクションは、要求の有効期間の間、データを保持するリポジトリの役割を果たします(Itemsコレクションの詳細については、記事「HttpContext.Items - a Per-Request Cache Store」を参照ください)。
  3. 処理を行うASP.NETページまたはHTTPハンドラのインスタンスを返します。
 大抵の場合、これらのルートハンドラクラスは、かなり決まりきった形式となります。ルーティングパラメータをHttpContext.Itemsコレクションに格納し、このURLのコンテンツを生成するASP.NETページのインスタンスを作成して返します。お決まりの形式になることから、ルートハンドラクラスの作成は、新しいルートの1つ1つに対し、以前作成したルートハンドラクラスとほとんど同一の処理を行う新しいルートハンドラクラスをいちいち作成するという、単調な作業となります。

 ASP.NET 3.5 SP1のASP.NETルーティングにはもう1つ、コンテンツを生成するASP.NETページに関する問題点があります。このページは、ルーティングパラメータを、HttpContext.Itemsコレクション(または、ルートハンドラクラスがパラメータを格納したそれ以外の場所)から読み出さなければなりません。また、ハイパーリンクやResponse.Redirectの呼び出しのために、ルーティングフレンドリなURL(Categories/<カテゴリ名>など)を生成する構文は、やや冗長で紛らわしいものになっています。

 ASP.NET 4.0のASP.NETルーティングでは、多様なルーティング関連のメソッドが新たに追加され、実際のASP.NETページへとマップするルーティングルールの定義がかなり簡素化されています。仲介的な役割を担うルートハンドラクラスを特別に作成する必要はなくなり、Global.asaxのルーティングルールから直接、ASP.NETページを参照できます。ルーティングルールでASP.NETページを指定すると、ルーティングパラメータが新しいRouteDataコレクションに自動的に格納されます。ASP.NETページからは、Page.RouteDataを介してRouteDataコレクションにアクセスできます。さらに.NET Framework 4.0では、カスタムパラメータコントロールが使用できるため、ASP.NETのデータソースコントロール(SqlDataSourceやLinqDataSourceなど)から、RouteDataコレクションの中の値を、宣言して使用できます。ルーティングフレンドリなURLを生成したり、ルーティングフレンドリなURLへとリダイレクトしたりするためのメソッドも提供されています。

 本稿では、ASP.NET 4.0におけるASP.NETルーティングの拡張点について説明します。本稿のダウンロード可能なデモプログラムの動作は、記事「Using ASP.NET Routing Without ASP.NET MVC」で紹介したプログラムと同じです。これはNorthwind Tradersのオンラインストアフロントとして機能するWeb Formsアプリケーションになります。ASP.NETルーティングを使用することにより、簡潔でSEOフレンドリなURLを生成します。例えば、/Categories/Allは全カテゴリを表示し、/Categories/Beveragesは「飲料」カテゴリ内の全商品を一覧表示し、/Products/Chaiは商品「チャイ」に関する情報を表示します。記事「Using ASP.NET Routing Without ASP.NET MVC」のデモプログラムは、ASP.NET 3.5 SP1のASP.NETルーティングの使用方法を示すものでした。本稿のデモプログラムでは、ASP.NET 4.0のASP.NETルーティングを使用しています。

 エンドユーザーの観点からは、2つのプログラムは機能も形式もまったく同じです。両者の違いは、ASP.NETルーティングを使用するためのWebサイトの設定に必要な処理と、Global.asaxで使用する構文、そしてコードビハインドページです。例えば、ASP.NET 3.5 SP1のASP.NETルーティングでは、プロジェクトにSystem.Web.Routingアセンブリを明示的に追加し、Web.configにマークアップを追加する必要がありました。ASP.NET 4.0では、このような処理は不要になりました。ASP.NET 4.0では、Global.asaxでルーティングルールを定義するために使用する構文と、コードビハインドページのコードも、短く、シンプルで、分かりやすいものになっています。

 以下では、ASP.NET 4.0のASP.NETルーティングを使用するための手順を、順を追って説明したいと思います。

ステップ0:前提条件

 このデモプログラムでは、ASP.NET 4.0に追加されたASP.NETルーティングの機能を使用します。従って、Visual Studio 2010か、Visual Web Developer 2010(またはそれ以降)の使用が必要になります。

ステップ1:Global.asaxにおいて、ルーティングルールを定義する

 ASP.NETルーティングを使用するには、アプリケーションの起動時に1つ以上のルートを定義しなければなりません。まず、プロジェクトにGlobal Application Classファイルタイプ(Global.asax)を追加します。Application_Startイベントにおいて、これにルートを登録します。

 Global.asaxに定義されたルートは、どのルートハンドラがどのURLパターンを処理するかを示すものです。MVCアプリケーションでは、「Controller/Action/ID」というパターンがよく使用され、/Products/View/Aniseed SyrupCategories/Edit/Beveragesといった形式の要求が、設定されたルートハンドラによって処理されます。アプリケーションにおけるルートを、かなり自由に定義できます。複数の部分からなるパターンを定義したり、指定されなかった部分に代入するデフォルト値を定義したり、特定の種類の入力の一部に対し、制約を設けたりすることもできます。

 本稿のデモプログラムは、簡単なデータ駆動のアプリケーションです。Northwindデータベースを使用し、次のような、一目でその意味が分かる形式のURLを使用します。

  • /Categories/All:データベースの全カテゴリを一覧表示する。
  • /Categories/<カテゴリ名>:指定されたカテゴリの全商品を一覧表示する。
  • /Products/<商品名>:指定された商品に関する情報を表示する。
 そこで、以下のコードに示すように、Global.asaxファイルの中のApplication_Startイベントハンドラに3つのルートを定義しました。

※注意
 RouteTableオブジェクトとRouteCollectionクラスは、System.Web.Routing名前空間に存在するため、この名前空間をインポートするか、System.Web.Routing.RouteTableというように、完全修飾クラス名を使用する必要があります。

void Application_Start(object sender, EventArgs e) 
{
   RegisterRoutes(RouteTable.Routes);
}

void RegisterRoutes(RouteCollection routes)
{
   // Register a route for Categories/All
   routes.MapPageRoute(
      "All Categories",      // Route name
      "Categories/All",      // Route URL
      "~/AllCategories.aspx" // Web page to handle route
   );

   // Route to handle Categories/{CategoryName}. 
   // The {*CategoryName} instructs the route to match all content after the first slash, which is needed b/c
   //  some category names contain a slash, as in the category "Meat/Produce"
   // See http://forums.asp.net/p/1417546/3131024.aspx for more information
   routes.MapPageRoute(
      "View Category",               // Route name
      "Categories/{*CategoryName}",  // Route URL
      "~/CategoryProducts.aspx"      // Web page to handle route
   );

   // Register a route for Products/{ProductName}
   routes.MapPageRoute(
      "View Product",           // Route name
      "Products/{ProductName}", // Route URL
      "~/ViewProduct.aspx"      // Web page to handle route
   );
} 
 Application_Startでは、RouteCollectionであるRouteTable.Routesを引数として、RegisterRoutesメソッド(そのすぐ下で定義されています)を呼び出します。RegisterRoutesメソッドでは、RouteCollectionクラスのMapPageRouteを呼び出します。MapPageRouteでは、ルーティングパターンとASP.NETページの間のルートマッピングを定義します。例えば、MapPageRouteの最初の呼び出しでは、Categories/Allというルートパターンを~/AllCategories.aspxというASP.NETページにマップする、「All Categories」という名前のルートを作成しています。

 続く2つのMapPageRouteに対する呼び出しでは、パラメータを持つルーティングパターンを作成しています。ルート「View Product」は、Products/{ProductName}というパターンを~/ViewProduct.aspxというASP.NETページにマップします。{ProductName}はパラメータであり、Products/<商品名>という形式のすべての要求が~/ViewProduct.aspxに引き渡されることを表します。すぐ後で説明しますが、~/ViewProduct.aspxからは、Page.RouteDataパラメータを介して、{ProductName}パラメータの値にアクセスできます。

ステップ2:要求を処理するASP.NETページを作成する

 ASP.NET 4.0では、特別なルートハンドラクラスを作成する必要はありません。MapPageRouteメソッドを使用すれば、その処理がすべて、裏で自動的に実行されます。従って残された作業は、要求(AllCategories.aspx、CategoryProducts.aspx、ViewProduct.aspx)を処理するASP.NETページを作成することだけです。デモプログラムのASP.NETページは、非常に簡単なものです。ルーティングパラメータによってCategoriesまたはProductsテーブルからデータベース結果を取得し、それにデータソースコントロールをプログラムによってバインドし、使用します。

 デモプログラムでは、データへのアクセスにLINQ-to-SQLツールを使用しています。App_Codeフォルダの中に、Northwind.dbmlというファイルがあり、そこでNorthwindDataContextクラスを作成します。ViewProduct.aspxページには、商品名、提供企業、単位あたり数量、価格などの関連情報を表示するために定義されたフィールドを持つ、DetailsViewコントロールがあります。このページのコードビハインドクラスのコードを、以下に示します(コードは一部省略されています)。

protected void Page_Load(object sender, EventArgs e)
{
   dvProductInfo.DataSource = new Product[] { Product };
   dvProductInfo.DataBind();
}

private Product _Product = null;
protected Product Product
{
   get
   {
      if (_Product == null)
      {
         string productName = Page.RouteData.Values["ProductName"] as string;

         NorthwindDataContext DataContext = new NorthwindDataContext();
         _Product = DataContext.Products.Where(p => p.ProductName == productName).SingleOrDefault();
      }

      return _Product;
   }
} 
 Page_Loadイベントハンドラにおいて、DetailsViewコントロールを、Productプロパティによって返されたProductオブジェクトにバインドしています。Productプロパティは、Page.RouteData.Values["ProductName"]という構文により、Page.RouteDataコレクションからURLの中の<商品名>パラメータの値を読み出します。そして、この<商品名>パラメータの値を用いたLINQクエリによって、その特定の商品に関する情報を取得します。

 以下のスクリーンショットは、動作中のViewProduct.aspxページを示したものです。ページのURLは/Products/Chaiで、ページにはチャイに関する詳細情報が表示されています(デモプログラムの他のスクリーンショットについては、記事「Using ASP.NET Routing Without ASP.NET MVC」を参照ください。この記事には、Categories/AllCategories/<カテゴリ名>の両ページのスクリーンショットが掲載されています)。

 これで終わりです。ASP.NET 4.0におけるASP.NETルーティングの設定は、以上ですべて完了しました。5つの処理が必要だったASP.NET 3.5 SP1に対し、ステップ数はわずか2つと、格段に容易になっていることが分かります。

ルーティングフレンドリなURLを生成する

 ハイパーリンクを作成したり、Response.Redirectによってユーザーをあるページから別のページへとリダイレクトしたりする場合には、ASP.NETページをその実際の名前で参照するよりも、Global.asaxに定義されたルーティングパターンを使用する方が理想的です。例えばViewProducts.aspxページには、Categories/<カテゴリ名>にリンクされた、その商品のカテゴリに含まれる全商品を一覧表示するページに戻るためのリンクがあります。<カテゴリ名>は、表示する商品を含むカテゴリの名前です。このようなルーティングフレンドリなURLを、Page.GetRouteUrlメソッドを用いて生成できます。このメソッドにはいくつかのオーバーロードメソッドがありますが、最も簡単なのは、ルートの名前とパラメータの値という2つの引数を持つものです。

 例えば、Categories/<カテゴリ名>ページに戻るための正しいURLを取得するには、以下の構文を使用します。

Page.GetRouteUrl("View Category", new { CategoryName = <カテゴリ名> }); 
 ここで、「View Category」はGlobal.asaxに定義されたルーティングルールの名前であり、<カテゴリ名>はURLの中のCategoryNameパラメータの値です。より具体的なコードを示すと、以下のようになります。

Page.GetRouteUrl("View Category", new { CategoryName = "Beverages" }); 
 Response.Redirectの新しいバージョンである、Response.RedirectToRouteという名前のメソッドも提供されています。Page.GetRouteUrlメソッドと同様に、Response.RedirectToRouteはルート名とパラメータ値を引数とし、適切な、ルーティングフレンドリなURLへとユーザーをリダイレクトします。以下に、特定の商品を紹介するページへとユーザーをリダイレクトする方法を示します。

Response.RedirectToRoute("View Product", new { ProductName = <商品名> }); 

まとめ

 ASP.NETルーティングは、.NET Frameworkにおける強力なライブラリです。開発者はこれを用いることで、アプリケーションで扱うURLを、実際の物理的なファイルから切り離すことができます。ASP.NET 3.5 SP1で導入されたASP.NETルーティングは当初、ASP.NET MVCアプリケーション向けに設計されていました。Web Formアプリケーションで使用することは可能でしたが、その設定には単調な作業の繰り返しが必要で、作成されるコードも、不要ではないかと感じるほど、重複の多いものでした。ASP.NET 4.0では、ASP.NETルーティングライブラリが強化され、より自由かつ直感的にWeb Formアプリケーションに使用できるようになりました。本稿で示したように、Global.asaxに数行のコードを記述するだけで、ルーティングパターンをASP.NETページにマップできます。特別なルートハンドラクラスを作成する必要はなくなりました。ASP.NETルーティングライブラリが裏で自動的に、ルーティングパラメータを、Pageクラスからアクセス可能なRouteDataコレクションに保存します。さらに、これらのRouteDataの値には、SqlDataSourceやObjectDataSourceといったデータソースコントロールから、宣言してアクセスできます。

 それでは、ハッピープログラミング!

参考資料

著者紹介

Scott Mitchell(Scott Mitchell)
【関連記事】
アクティブコアの「レコメンドウエアハウス」が ASP.NET に正式対応
ASP.NETアプリケーションにカラーピッカーコントロールを追加する
ASP.NETで画像のアップロードとサムネイルの作成を行うには
ASP.NETで構築したWebサイトからFlickr.Netライブラリを使ってFlickrの画像にアクセスする
ASP.NETマスターページの小技

New Topics

Special Ad

ゆりかごからロケットまで、すべての乗り物をエンジョイ
ゆりかごからロケットまで、すべての乗り物をエンジョイ えん乗り」は、ゆりかごからロケットまで、すべての乗り物をエンジョイする、ニュース、コラム、動画などをお届けします! てんこ盛りをエンジョイするのは こちらから

Hot Topics

IT Job

Interviews / Specials

Popular

Access Ranking

Partner Sites