使用 ASP.NET Web Form路由Scott Allen代碼下載位置:MSDN 程式碼程式庫
線上瀏覽代碼 目錄什麼是路由?
URL 重寫的簡史
路由和路由處理常式
配置 ASP.NET 的路由
配置路由
方案路由處理常式
路由和安全性
URL 產生
路由總結
Microsoft .NET Framework 3.5 Service Pack 1 在 ASP.NET 運行時中引入了路由引擎。路由引擎可以從響應傳入 HTTP 要求的實際 Web Form中分離該請求中的 URL,使您能夠為 Web 應用程式構建友好的 URL。儘管在以前版本的 ASP.NET 中也一直都能夠使用友好的 URL,但路由引擎卻提供了一種更簡單、更明晰和更容易測試的方法。路由引擎最初是 ASP.NET 模型視圖控制器 (MVC) 架構的一部分,在撰寫本文時它仍處於預演階段。但是,Microsoft 將路由邏輯封裝到了 System.Web.Routing 程式集中,並隨同 SP1 發布了該程式集。目前該程式集使用 ASP.NET 動態資料功能(它們也隨 SP1 一起發布)為網站提供路由,但在本專欄中,我將介紹如何通過 ASP.NET Web Form來使用路由功能。
什麼是路由?假設您有一個名為 RecipeDisplay.aspx 的 ASP.NET Web Form,此表單位於一個名為 Web Forms 的檔案夾中。使用此 Web Form查看方案時,傳統方法是構建一個指向該表單實際位置的 URL,並將某些資料通過編碼方式嵌入到查詢字串中,以告知 Web Form要顯示的方案。此類 URL 的結尾可能如下所示:/WebForms/RecipeDisplay.aspx?id=5,其中數字 5 代表在一個充滿方案的資料庫表中的主索引值。路由從本質上來說就是把一個 URL 端點分解成多個參數,然後使用這些參數將 HTTP 要求處理引導至特定的組件。讓我們以 URL /recipe/5 為例。藉助正確的路由配置,您仍可以使用 Web Form RecipeDisplay.aspx 來響應此 URL。此時 URL 不再代表實際的路徑。單詞 recipe 變為代表一個參數,路由引擎可以用它找到處理 recipe 請求的組件。數字 5 代表第二個參數,在處理期間用它顯示某個特定的 recipe。此時不宜通過編碼將資料庫關鍵字嵌入 URL 中,更好的做法是使用形如 /recipe/tacos 的 URL。此 URL 不但包括足夠多的參數來顯示特定的 recipe,還非常便於人們閱讀理解,它可以為終端使用者揭示其意圖,並包括一些重要的關鍵字供搜尋引擎使用。
URL 重寫的簡史在 ASP.NET 中,使用以 /recipe/tacos 結尾的 URL 時,從傳統上而言需要有人來處理 URL 重寫架構。有關 URL 重寫的詳細資料,請參閱 Scott Mitchell 撰寫的權威文章“在 ASP.NET 中執行 URL 重寫”。該文描述了在 ASP.NET 中使用 HTTP 模組和 HttpContext 類的靜態 RewritePath 方法重寫 URL 的常見途徑。Scott 的文章還詳細說明了友好且可改動 URL 的優點。在過去曾使用過 RewritePath API 的使用者可能非常清楚重寫方法中的某些怪異現象和缺點。RewritePath 面臨的主要問題是在處理請求的過程中該方法如何更改所使用的虛擬路徑。使用 URL 重寫時,需要設定每個 Web Form的回傳目標(通常通過在請求過程中再次重寫 URL 來實現),以避免回傳轉到內部已重寫的 URL。此外,大多數開發人員在實現 URL 重寫時都採用單向轉換模式,因為無法通過任何簡單的機制使 URL 重寫邏輯雙向工作。例如,要賦予 URL 重寫邏輯一個公眾對應 URL 並使該邏輯返回 Web Form的內部 URL 非常容易。但是,要為 Web Form的內部 URL 賦予重寫邏輯並使其返回進入表單所需的公用 URL 卻很困難。產生到隱藏在被重寫的 URL 中的其他 Web Form的超連結時,後者會非常有用。本專欄的其餘部分介紹了 URL 路由引擎如何解決這些問題。圖 1 路由、路由處理常式和路由模組路由和路由處理常式URL 路由引擎中包含三種基本角色:路由、路由處理常式和路由模組。路由將 URL 與路由處理常式關聯在一起。Route 類來自 System.Web.Routing 命名空間,它的執行個體在運行時會代表一個路由並描述該路由的參數和約束。路由處理常式繼承自 System.Web.Routing.IRouteHandler 介面。此介面要求路由處理常式實現 GetHttpHandler 方法,而此方法將返回一個實現 IHttpHandler 介面的對象。在最開始的時候,IHttpHandler 介面即已是 ASP.NET 的一部分,而 Web Form (System.Web.UI.Page) 則屬於 IhttpHandler。在使用 Web Form路由時,路由處理常式需要定位、執行個體化並返回正確的 Web Form。最終,路由模組嵌入到了 ASP.NET 處理管道中。該模組會攔截傳入的請求、檢查 URL 並判斷是否存在任何已定義的匹配路由。該模組將檢索匹配路由的相關路由處理常式,並向路由處理常式申請處理該請求的 IhttpHandler。我提到過的三個主要類型如圖 1 所示。在下一節中,我將展示這三種角色的工作方式。
配置 ASP.NET 的路由要配置 ASP.NET 網站或 Web 應用程式的路由功能,首先需要添加一個對 System.Web.Routing 程式集的引用。.NET Framework 3.5 的 SP1 安裝程式會將此程式集安裝到全域組件快取中,您可以在標準的“Add Reference”(添加引用)對話方塊內找到該程式集。您還需要在 ASP.NET 管道中配置路由模組。路由模組是標準的 HTTP 模組。對於 IIS 6.0 和更早版本以及 Visual Studio Web 程式開發伺服器,可以使用 web.config 的 <httpModules> 來安裝模組,具體如下所示:
<httpModules> <add name="RoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <!-- ... --></httpModules>
要在 IIS 7.0 中運行帶路由功能的網站,需要用到 web.config 中的兩個條目。第一個條目是 URL 路由模組配置,位於 <system.webServer> 的 <modules> 中。此外還需要 <system.webServer> 的 <handlers> 中的一個條目來處理對 UrlRouting.axd 的請求。這兩個條目如圖 2 所示。另請參閱側欄“IIS 7.0 配置條目”。 圖 2 URL 路由模組配置
<system.webServer> <modules runAllManagedModulesForAllRequests="true"> <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <!-- ... --> </modules> <handlers> <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <!-- ... --> </handlers></system.webServer>
將 URL 路由模組配置到管道中後,它會將其自身綁定到 PostResolveRequestCache 和 PostMapRequestHandler 事件上。圖 3 顯示了管道事件的一個子集。URL 重寫實現通常在 BeginRequest 事件程序中執行其工作,該事件是在一個請求中最早被觸發的事件。使用 URL 路由時,路由處理常式會在 PostResolveRequestCache 階段(此階段發生在身分識別驗證、授權以及緩衝查詢等處理階段之後)進行路由匹配和選擇。我會在本專欄後面的內容中再次討論此事件定時的含義。圖 3 HTTP 要求
配置路由路由和路由處理常式的聯絡非常緊密,但我首先著眼於路由配置代碼。路由引擎的 RouteTable 類會通過其靜態 Routes 屬性公開 RouteCollection。首先您必須在此集合內配置所有自訂路由,然後應用程式才能開始執行第一個請求,這意味著您需要使用 global.asax 檔案和 Application_Start 事件。圖 4 顯示了要讓 "/recipe/brownies" 進入 RecipeDisplay.aspx Web Form必須使用的路由註冊代碼。在 RouteCollection 類中,Add 方法的參數包括一個友好的路由名稱,後跟路由本身。Route 建構函式的第一個參數是 URL 模式。該模式由多個 URL 片段組成,這些片段將出現在指向此應用程式的 URL 的末尾(且在進入該應用程式的根所需的任何片段之後)。而對於根位於 localhost/food/ 中的應用程式,圖 4 中的路由模式將匹配 localhost/food/recipe/brownies。 圖 4 /recipe/brownies 的路由註冊代碼
protected void Application_Start(object sender, EventArgs e){ RegisterRoutes();}private static void RegisterRoutes(){ RouteTable.Routes.Add( "Recipe", new Route("recipe/{name}", new RecipeRouteHandler( "~/WebForms/RecipeDisplay.aspx")));}
IIS 7.0 配置條目
如果您希望如我在本例中所示使用不具擴充性的 URL,則需要為 runAllManagedModulesForAllRequests 屬性提供一個 true 值。另外,為 UrlRouting.axd 配置 HTTP 處理常式可能有些奇怪。這是為了使路由引擎能夠在 IIS 7.0 中進行路由所採用的一種簡單解決方案。實際上 UrlRouting 模組會將傳入 URL 重寫為 ~/UrlRouting.axd,而它會將 URL 重寫回原始的傳入 URL。很可能 IIS 的未來版本會與路由引擎完美整合,而不再需要使用此解決方案。大括弧中的內容表示參數,路由引擎會自動提取該處的值並將其放入名稱/值字典中,在請求持續期間,該字典將始終存在。在前一個 localhost/food/recipe/brownies 樣本中,路由引擎將提取值 "brownies" 並使用 "name" 作為關鍵字將其儲存到字典中。在我介紹路由處理常式的代碼時,您會瞭解到如何來使用字典。您可以根據需要向 RouteTable 中添加任意數量的路由,但路由的排列順序非常重要。路由引擎會根據集合中路由出現的順序來使用這些路由測試所有傳入 URL,引擎會選擇第一個與模式比對的路由。為此,您應首先添加最具特殊性的路由。如果以 URL 模式 "{category}/{subcategory}" 在方案路由之前添加了一個通用路由,則路由引擎永遠也不會發現該方案路由。另外還要注意——路由引擎在執行模式比對時是不區分大小寫。Route 建構函式的重載版本允許您建立預設參數值並應用約束。當傳入 URL 中的參數不包含任何值時,Defaults 允許您指定路由引擎的預設值以將其放入名稱/值參數字典中。例如,當路由引擎發現一個不包含名稱值(如 localhost/food/recipe)的方案 URL 時,可使用 "brownies" 作為預設的方案名稱。