URL ルーティング

作成者 : Erik Reitan

Wingtip Toys サンプル プロジェクトのダウンロード (C#) または 電子書籍のダウンロード (PDF)

このチュートリアル シリーズでは、ASP.NET 4.5 と Microsoft Visual Studio Express 2013 for Web を使用して ASP.NET Web Forms アプリケーションを構築する基本について説明します。 C# ソース コードを含むVisual Studio 2013 プロジェクトは、このチュートリアル シリーズに付属しています。

このチュートリアルでは、URL ルーティングをサポートするように Wingtip Toys サンプル アプリケーションを変更します。 ルーティングを使用すると、Web アプリケーションで、検索エンジンによってわかりやすく、覚えやすく、サポートが向上した URL を使用できます。 このチュートリアルは、前のチュートリアル 「メンバーシップと管理」に基づいており、Wingtip Toys チュートリアル シリーズの一部です。

ここでは、次の内容について学習します。

  • ASP.NET Web Forms アプリケーションのルートを登録する方法。
  • Web ページにルートを追加する方法。
  • ルートをサポートするためにデータベースからデータを選択する方法。

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

URL ルーティングを使用すると、物理ファイルにマップされない要求 URL を受け入れるようにアプリケーションを構成できます。 要求 URL は、ユーザーが Web サイト上のページを検索するためにブラウザーに入力する URL です。 ルーティングを使用して、ユーザーにとって意味的に意味のある URL を定義し、検索エンジンの最適化 (SEO) に役立つ URL を定義します。

既定では、Web Forms テンプレートには ASP.NET フレンドリ URL が含まれています。 基本的なルーティング作業の多くは、 フレンドリ URL を使用して実装されます。 ただし、このチュートリアルでは、カスタマイズされたルーティング機能を追加します。

URL ルーティングをカスタマイズする前に、Wingtip Toys サンプル アプリケーションは次の URL を使用して製品にリンクできます。

https://localhost:44300/ProductDetails.aspx?productID=2

URL ルーティングをカスタマイズすることで、Wingtip Toys サンプル アプリケーションは、読みやすい URL を使用して同じ製品にリンクします。

https://localhost:44300/Product/Convertible%20Car

ルート

ルートとは、ハンドラーにマップされている URL のパターンです。 ハンドラーには、Web Forms アプリケーションの .aspx ファイルなどの物理ファイルを指定できます。 ハンドラーは、要求を処理するクラスにすることもできます。 ルートを定義するには、URL パターン、ハンドラー、および必要に応じてルートの名前を指定して、Route クラスのインスタンスを作成します。

アプリケーションにルートを追加するには、 クラスの Route 静的 Routes プロパティに オブジェクトを RouteTable 追加します。 Routes プロパティは、 RouteCollection アプリケーションのすべてのルートを格納するオブジェクトです。

URL パターン

URL パターンには、リテラル値と変数プレースホルダー (URL パラメーターと呼ばれます) を含めることができます。 リテラルとプレースホルダーは、スラッシュ (/) 文字で区切られた URL のセグメントに配置されます。

Web アプリケーションに対する要求が行われると、URL はセグメントとプレースホルダーに解析され、変数値は要求ハンドラーに提供されます。 このプロセスは、クエリ文字列内のデータを解析して要求ハンドラーに渡す方法と似ています。 どちらの場合も、変数情報は URL に含まれ、キーと値のペアの形式でハンドラーに渡されます。 クエリ文字列の場合、キーと値の両方が URL 内にあります。 ルートの場合、キーは URL パターンで定義されているプレースホルダー名であり、URL には値のみが含まれます。

URL パターンでは、プレースホルダーを中かっこ ( {} ) で囲んで定義します。 1 つのセグメントに複数のプレースホルダーを定義できますが、プレースホルダーはリテラル値で区切る必要があります。 たとえば、 {language}-{country}/{action} は有効なルート パターンです。 ただし、 {language}{country}/{action} プレースホルダー間にリテラル値や区切り記号がないため、有効なパターンではありません。 そのため、ルーティングでは、言語プレースホルダーの値と国プレースホルダーの値を区切る場所を決定できません。

ルートのマッピングと登録

Wingtip Toys サンプル アプリケーションのページへのルートを含める前に、アプリケーションの起動時にルートを登録する必要があります。 ルートを登録するには、イベント ハンドラーを Application_Start 変更します。

  1. ソリューション エクスプローラー of Visual Studio で、Global.asax.cs ファイルを見つけて開きます。

  2. 次のように、黄色で強調表示されたコードを Global.asax.cs ファイルに追加します。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Optimization;
    using System.Web.Routing;
    using System.Web.Security;
    using System.Web.SessionState;
    using System.Data.Entity;
    using WingtipToys.Models;
    using WingtipToys.Logic;
    
    namespace WingtipToys
    {
        public class Global : HttpApplication
        {
            void Application_Start(object sender, EventArgs e)
            {
              // Code that runs on application startup
              RouteConfig.RegisterRoutes(RouteTable.Routes);
              BundleConfig.RegisterBundles(BundleTable.Bundles);
    
              // Initialize the product database.
              Database.SetInitializer(new ProductDatabaseInitializer());
    
              // Create custom role and user.
              RoleActions roleActions = new RoleActions();
              roleActions.AddUserAndRole();
    
              // Add Routes.
              RegisterCustomRoutes(RouteTable.Routes);
            }
    
            void RegisterCustomRoutes(RouteCollection routes)
            {
              routes.MapPageRoute(
                  "ProductsByCategoryRoute",
                  "Category/{categoryName}",
                  "~/ProductList.aspx"
              );
              routes.MapPageRoute(
                  "ProductByNameRoute",
                  "Product/{productName}",
                  "~/ProductDetails.aspx"
              );
            }
        }
    }
    

Wingtip Toys サンプル アプリケーションが起動すると、イベント ハンドラーが Application_Start 呼び出されます。 このイベント ハンドラーの最後に、 RegisterCustomRoutes メソッドが呼び出されます。 メソッドは RegisterCustomRoutes 、 オブジェクトの メソッドを MapPageRoute 呼び出して各ルートを RouteCollection 追加します。 ルートは、ルート名、ルート URL、および物理 URL を使用して定義されます。

最初のパラメーター ("ProductsByCategoryRoute") はルート名です。 これは、必要なときにルートを呼び出すために使用されます。 2 番目のパラメーター ("Category/{categoryName}") は、コードに基づいて動的にできるフレンドリ置換 URL を定義します。 このルートは、データに基づいて生成されるリンクをデータ コントロールに設定する場合に使用します。 ルートは次のように表示されます。

routes.MapPageRoute(
      "ProductsByCategoryRoute",
      "Category/{categoryName}",
      "~/ProductList.aspx"
  );

ルートの 2 番目のパラメーターには、中かっこ ({ }) で指定された動的な値が含まれています。 この場合、 categoryName は、適切なルーティング パスを決定するために使用される変数です。

Note

Optional

メソッドを別のクラスに移動すると、コードの RegisterCustomRoutes 管理が簡単になる場合があります。 [ロジック] フォルダーで、別RouteActionsのクラスを作成します。 上記 RegisterCustomRoutes のメソッドを Global.asax.cs ファイルから新しい RoutesActions クラスに移動します。 RoleActionsGlobal.asax.cs ファイルから メソッドを呼び出すRegisterCustomRoutes方法の例として、 クラスと createAdmin メソッドを使用します。

イベント ハンドラーの先頭にある オブジェクトを RegisterRoutes 使用した RouteConfig メソッド呼び出しにも Application_Start 気付いたかもしれません。 この呼び出しは、既定のルーティングを実装するために行われます。 Visual Studio のWeb Forms テンプレートを使用してアプリケーションを作成したときに、既定のコードとして含まれていました。

ルート データの取得と使用

前述のように、ルートを定義できます。 Global.asax.cs ファイルのイベント ハンドラーに追加Application_Startしたコードによって、定義可能なルートが読み込まれます。

ルートの設定

ルートでは、コードを追加する必要があります。 このチュートリアルでは、モデル バインドを使用して、データ コントロールからデータを使用してルートを生成するときに使用されるオブジェクトを取得 RouteValueDictionary します。 オブジェクトには RouteValueDictionary 、製品の特定のカテゴリに属する製品名の一覧が含まれます。 データとルートに基づいて、製品ごとにリンクが作成されます。

カテゴリと製品のルートを有効にする

次に、 を使用 ProductsByCategoryRoute するようにアプリケーションを更新し、各製品カテゴリ リンクに含める正しいルートを決定します。 また、 ProductList.aspx ページを更新して、各製品のルーティング リンクを含めます。 リンクは変更前と同じように表示されますが、リンクでは URL ルーティングが使用されるようになります。

  1. ソリューション エクスプローラーで、Site.Master ページがまだ開いていない場合は開きます。

  2. "categoryList" という名前の ListView コントロールを更新し、変更が黄色で強調表示されているので、マークアップは次のように表示されます。

    <asp:ListView ID="categoryList"  
        ItemType="WingtipToys.Models.Category" 
        runat="server"
        SelectMethod="GetCategories" >
        <ItemTemplate>
            <b style="font-size: large; font-style: normal">
            <a href="<%#: GetRouteUrl("ProductsByCategoryRoute", new {categoryName = Item.CategoryName}) %>">
                <%#: Item.CategoryName %>
            </a>
            </b>
        </ItemTemplate>
        <ItemSeparatorTemplate>  |  </ItemSeparatorTemplate>
    </asp:ListView>
    
  3. ソリューション エクスプローラーで、ProductList.aspx ページを開きます。

  4. ItemTemplateProductList.aspx ページの要素を黄色で強調表示された更新プログラムで更新すると、マークアップは次のように表示されます。

    <ItemTemplate>
      <td runat="server">
        <table>
          <tr>
            <td>
              <a href="<%#: GetRouteUrl("ProductByNameRoute", new {productName = Item.ProductName}) %>">
                <image src='/Catalog/Images/Thumbs/<%#:Item.ImagePath%>'
                  width="100" height="75" border="1" />
              </a>
            </td>
          </tr>
          <tr>
            <td>
              <a href="<%#: GetRouteUrl("ProductByNameRoute", new {productName = Item.ProductName}) %>">
                <%#:Item.ProductName%>
              </a>
              <br />
              <span>
                <b>Price: </b><%#:String.Format("{0:c}", Item.UnitPrice)%>
              </span>
              <br />
              <a href="/AddToCart.aspx?productID=<%#:Item.ProductID %>">
                <span class="ProductListItem">
                  <b>Add To Cart<b>
                </span>
              </a>
            </td>
          </tr>
          <tr>
            <td>&nbsp;</td>
          </tr>
        </table>
        </p>
      </td>
    </ItemTemplate>
    
  5. ProductList.aspx.cs の分離コードを開き、黄色で強調表示されている次の名前空間を追加します。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using WingtipToys.Models;
    using System.Web.ModelBinding;
    using System.Web.Routing;
    
  6. GetProducts分離コード (ProductList.aspx.cs) の メソッドを次のコードに置き換えます。

    public IQueryable<Product> GetProducts(
        [QueryString("id")] int? categoryId,
        [RouteData] string categoryName)
    {
        var _db = new WingtipToys.Models.ProductContext();
        IQueryable<Product> query = _db.Products;
    
        if (categoryId.HasValue && categoryId > 0)
        {
            query = query.Where(p => p.CategoryID == categoryId);
        }
    
        if (!String.IsNullOrEmpty(categoryName))
        {
            query = query.Where(p =>
                String.Compare(p.Category.CategoryName,
                categoryName) == 0);
        }
        return query;
    }
    

製品の詳細のコードを追加する

次に、ProductDetails.aspx ページの分離コード (ProductDetails.aspx.cs) を更新して、ルート データを使用します。 新しい GetProduct メソッドは、ユーザーが古い非ルーティング URL を使用するリンクブックマークを持っている場合のクエリ文字列値も受け入れることに注意してください。

  1. GetProduct分離コード (ProductDetails.aspx.cs) の メソッドを次のコードに置き換えます。

    public IQueryable<Product> GetProduct(
            [QueryString("ProductID")] int? productId,
            [RouteData] string productName)
    {
        var _db = new WingtipToys.Models.ProductContext();
        IQueryable<Product> query = _db.Products;
        if (productId.HasValue && productId > 0)
        {
            query = query.Where(p => p.ProductID == productId);
        }
        else if (!String.IsNullOrEmpty(productName))
        {
            query = query.Where(p =>
                  String.Compare(p.ProductName, productName) == 0);
        }
        else
        {
            query = null;
        }
        return query;
    }
    

アプリケーションの実行

これでアプリケーションを実行して、更新されたルートを確認できます。

  1. F5 キーを押して Wingtip Toys サンプル アプリケーションを実行します。
    ブラウザーが開き、 Default.aspx ページが表示されます。
  2. ページの上部にある [ 製品 ] リンクをクリックします。
    すべての製品が ProductList.aspx ページに表示されます。 ブラウザーには、次の URL (ポート番号を使用) が表示されます。
    https://localhost:44300/ProductList
  3. 次に、ページの上部付近にある [Cars ] カテゴリ リンクをクリックします。
    ProductList.aspx ページには車のみが表示されます。 ブラウザーには、次の URL (ポート番号を使用) が表示されます。
    https://localhost:44300/Category/Cars
  4. ページ ("コンバーチブル カー") に一覧表示されている最初の車の名前を含むリンクをクリックして、製品の詳細を表示します。
    ブラウザーには、次の URL (ポート番号を使用) が表示されます。
    https://localhost:44300/Product/Convertible%20Car
  5. 次に、(ポート番号を使用して) 次のルーティングされていない URL をブラウザーに入力します。
    https://localhost:44300/ProductDetails.aspx?productID=2
    このコードでは、ユーザーがブックマークされたリンクがある場合に、クエリ文字列を含む URL が認識されます。

まとめ

このチュートリアルでは、カテゴリと製品のルートを追加しました。 モデル バインドを使用するデータ コントロールとルートを統合する方法について学習しました。 次のチュートリアルでは、グローバル エラー処理を実装します。

その他のリソース

ASP.NET Friendly URL
メンバーシップ、OAuth、SQL Databaseを使用してセキュリティで保護された ASP.NET Web Forms アプリをAzure App Serviceにデプロイする
Microsoft Azure - 無料試用版