使用 apache 時可以方便的使用 mod_rewrite
,來做重寫網址的功能,而到了 IIS 則可使用 IIS URL Rewrite Module
來達成,而 .NET 3.5 SP1 之後新增加了 System.Web.Routing
的組件,他可以做到和 IIS URL Rewrite Module 類似的事情,但是在背後運作的機制和使用上有不同之處,在本篇就不多做介紹。
本篇將說明如何使用 Routing
組件來達成 URL 重寫的功能,例如 Blog.aspx?User=emn178
的網址,以 emn178/Blog
的樣式呈現,此篇文章以實作 IRouteHandler
方式處理。
開發模式
要在開發時套用此功能,依照以下步驟設定
- 專案 [加入參考] => [.NET] => [System.Web.Routing] 組件
- VS2008 不會自動將模組加入
Web.config
,所以需要額外加入以下內容,請找到相對應的位置加入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <configuration> <system.web> <compilation debug="true"> <assemblies> <add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> </assemblies> </compilation> <httpModules> <add name="RoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </httpModules> </system.web> <system.webServer> <modules> <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> </configuration>
|
- 實作 Handler,例如建立
BlogRouteHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class BlogRouteHandler : IRouteHandler { private string virtualPath;
public BlogRouteHandler(string virtualPath) { this.virtualPath = virtualPath; }
public IHttpHandler GetHttpHandler(RequestContext requestContext) { string origQueryStr = HttpContext.Current.Request.QueryString.ToString(); string queryStr = "?User=" + requestContext.RouteData.Values["User"];
if (!string.IsNullOrEmpty(origQueryStr)) queryStr += "&" + origQueryStr; HttpContext.Current.RewritePath(string.Concat(virtualPath, queryStr));
return BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page)) as Page; } }
|
- 如果沒有
Global.asax
則[新增項目] => [全域應用程式類別] - 於
Global.asax
中加入 Routing
註冊函式
1 2 3 4 5 6 7 8 9 10
| void Application_Start(object sender, EventArgs e) { RegisterRoutes(RouteTable.Routes); }
public static void RegisterRoutes(RouteCollection routes) { routes.Add(new Route("{User}/blog", new BlogRouteHandler("~/Blog.aspx"))); }
|
說明
由以上範例可發現,new Route("{User}/blog", ...)
表示你的規則,大括弧表示會變動的部分,變動的部分會傳入 GetHttpHandler
中的 requestContext.RouteData
自訂更多的規則
假設現在要新增 Blog.aspx?User=emn178&ArticleID=123
變成 emn178/Blog/123
的規則,而原來的規則也同時存在,將 RegisterRoutes
修改為
1 2 3 4 5
| public static void RegisterRoutes(RouteCollection routes) { routes.Add(new Route("{User}/blog", new BlogRouteHandler("~/Blog.aspx"))); routes.Add(new Route("{User}/blog/{ArticleID}", new BlogRouteHandler("~/Blog.aspx"))); }
|
BlogRouteHandler
修改為
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class BlogRouteHandler : IRouteHandler { private string virtualPath;
public BlogRouteHandler(string virtualPath) { this.virtualPath = virtualPath; }
public IHttpHandler GetHttpHandler(RequestContext requestContext) { string origQueryStr = HttpContext.Current.Request.QueryString.ToString(); string queryStr = "?User=" + requestContext.RouteData.Values["User"]; if (requestContext.RouteData.Values["ArticleID"] != null) queryStr += "?ArticleID=" + requestContext.RouteData.Values["ArticleID"];
if (!string.IsNullOrEmpty(origQueryStr)) queryStr += "&" + origQueryStr; HttpContext.Current.RewritePath(string.Concat(virtualPath, queryStr));
return BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page)) as Page; } }
|
套用到 IIS6
Routing 的規則在 IIS6 下會變成目錄不存在而無法顯示網頁,可以用以下的方式讓他交由 ASP.NET 去處理
- 進入 IIS 管理頁面,在你的網頁應用程式按右鍵 => [內容]
- 於目錄的頁籤下點擊[設定]
- 接著點擊[新增]來新增對應
- 執行檔選擇 .NET Framework 的 aspnet_isapi.dll,例如:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll
- 副檔名輸入 .*
- 指令動詞選擇[限制於]並輸入 GET,HEAD,POST,DEBUG
- 不勾選[檢查檔案是否存在]
套用到 IIS7
IIS7 則不需額外設定就可使用