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專案可供本教學課程系列使用。

在本教學課程中,您將修改 Wingtip Toys 範例應用程式以支援 URL 路由。 路由可讓您的 Web 應用程式使用易記、更容易記住的 URL,以及搜尋引擎更妥善支援。 本教學課程是以上一個教學課程「成員資格與管理」為基礎,並屬於 Wingtip Toys 教學課程系列。

您將學到什麼:

  • 如何註冊 ASP.NET Web Forms應用程式的路由。
  • 如何將路由新增至網頁。
  • 如何從資料庫選取資料以支援路由。

ASP.NET 路由概觀

URL 路由可讓您設定應用程式以接受未對應至實體檔案的要求 URL。 要求 URL 只是使用者在瀏覽器中輸入的 URL,以在您的網站上尋找頁面。 您可以使用路由來定義對使用者具有語意意義的 URL,並可協助搜尋引擎優化 (SEO) 。

根據預設,Web Form範本包含易記 URL ASP.NET。 大部分的基本路由工作都會使用 易記 URL來實作。 不過,在本教學課程中,您將新增自訂路由功能。

自訂 URL 路由之前,Wingtip Toys 範例應用程式可以使用下列 URL 連結至產品:

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

藉由自訂 URL 路由,Wingtip Toys 範例應用程式會使用更容易閱讀的 URL 連結至相同的產品:

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

路由

「路由」是一種對應到處理常式的 URL 模式。 處理常式可以是實體檔案,例如Web Form應用程式中的 .aspx 檔案。 處理常式也可以是處理要求的類別。 若要定義路由,您可以藉由指定 URL 模式、處理常式,以及選擇性地指定路由的名稱,以建立 Route 類別的實例。

您可以將 物件新增至 類別的 RouteTable 靜態 Routes 屬性,以將路由新增 Route 至應用程式。 Route 屬性是物件 RouteCollection ,可儲存應用程式的所有路由。

URL 模式

URL 模式可以包含常值和變數預留位置, (稱為 URL 參數) 。 常值和預留位置位於 URL 的區段中,以斜線分隔 (/) 字元。

當您對 Web 應用程式提出要求時,URL 會剖析成區段和預留位置,並將變數值提供給要求處理常式。 此程式類似于查詢字串中的資料剖析並傳遞至要求處理常式的方式。 在這兩種情況下,變數資訊都會包含在 URL 中,並以機碼/值組的形式傳遞至處理常式。 針對查詢字串,索引鍵和值都在 URL 中。 對於路由,索引鍵是 URL 模式中定義的預留位置名稱,而且只有值位於 URL 中。

在 URL 模式中,您可以將預留位置括在大括弧 ( {} ) 中來定義預留位置。 您可以在區段中定義多個預留位置,但預留位置必須以常值分隔。 例如, {language}-{country}/{action} 是有效的路由模式。 不過, {language}{country}/{action} 不是有效的模式,因為預留位置之間沒有常值或分隔符號。 因此,路由無法判斷將語言預留位置的值與國家/地區預留位置的值分隔的位置。

對應和註冊路由

您必須先在應用程式啟動時註冊路由,才能包含 Wingtip Toys 範例應用程式的頁面路由。 若要註冊路由,您將修改 Application_Start 事件處理常式。

  1. Solution Explorer 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 藉由呼叫 物件的 方法 RouteCollectionMapPageRoute 新增每個路由。 路由是使用路由名稱、路由 URL 和實體 URL 來定義。

第一個參數 (「 ProductsByCategoryRoute 」) 是路由名稱。 當需要路由時,它會用來呼叫路由。 第二個參數 (「 Category/{categoryName} 」) 定義易記的取代 URL,這些 URL 可以根據程式碼進行動態。 當您在資料控制項中填入以資料為基礎的連結時,就會使用此路由。 路由如下所示:

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

路由的第二個參數包含大括弧所指定的動態值 ({ }) 。 在此情況下, categoryName 是用來判斷適當路由路徑的變數。

注意

選擇性

您可以將 方法移至 RegisterCustomRoutes 個別類別,以更輕鬆地管理程式碼。 在 Logic 資料夾中,建立個別 RouteActions 的類別。 將上述 RegisterCustomRoutes 方法從 Global.asax.cs 檔案移至新的 RoutesActions 類別。 RoleActions使用 類別和 createAdmin 方法作為如何從Global.asax.cs檔案呼叫 RegisterCustomRoutes 方法的範例。

您可能也注意到 RegisterRoutes 在事件處理常式開頭 Application_Start 使用 RouteConfig 物件呼叫方法。 此呼叫會實作預設路由。 當您使用 Visual Studio 的 Web Form 範本建立應用程式時,它已包含為預設程式碼。

擷取和使用路由資料

如上所述,可以定義路由。 您在Global.asax.cs檔案中新增至 Application_Start 事件處理常式的程式碼會載入可定義的路由。

設定路由

路由會要求您新增其他程式碼。 在本教學課程中,您將使用模型系結來擷取 RouteValueDictionary 使用資料控制項的資料產生路由時所使用的物件。 物件 RouteValueDictionary 將包含屬於特定產品類別的產品名稱清單。 系統會根據資料和路由為每個產品建立連結。

啟用類別和產品的路由

接下來,您將更新應用程式,以使用 ProductsByCategoryRoute 來判斷每個產品類別連結要包含的正確路由。 您也會更新 ProductList.aspx 頁面,以包含每個產品的路由連結。 連結會在變更之前顯示,不過連結現在會使用 URL 路由。

  1. Solution Explorer中,如果尚未開啟,請開啟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. Solution Explorer中,開啟ProductList.aspx頁面。

  4. 使用 ItemTemplate 黃色醒目提示的更新來更新 ProductList.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.cs) ProductDetails.aspx 頁面的程式碼後置 (,以使用路由資料。 請注意,新 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. 接下來,按一下頁面頂端附近的 [汽車 ] 類別連結。
    只有汽車會顯示在 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 易記 URL
將具有成員資格、OAuth 和SQL Database的安全 ASP.NET Web Forms應用程式部署至 Azure App Service
Microsoft Azure - 免費試用