ASP.NET路由[ASP.NET Routing]
ASP.NET路由允許你在使用URL時不必匹配到網站中具體的文件,因為這個URL不必匹配到一個文件,你使用了描述用戶行為且更容易被用戶理解的URL。
ASP.NET MVC框架和ASP.NET動態數據(Dynamic Data)擴展路由為MVC應用和動態數據應用增加了特色。
在不使用路由的ASP.NET應用中,一個新的請求會被映射到一個物理文件並由該文件處理這個請求,例如一個.aspx文件。例如,如下請求http://server/application/Products.aspx?id=4會題映射到一個包含代碼和標簽來向瀏覽器渲染響應的Products.aspx文件。Web頁面人員使用id=4的查詢字符來確定顯示的內容。
使用ASP.NET路由,你可以定義映射請求-處理程序(request-handler)文件的URL模式,但沒必要在將這些文件的名字包含在這個URL中。除此之外,你還可以通過在URL模式中使用占位符來向請求處理程序傳輸變量數據,而不必使用查詢字符串。
例如,如下請求 http://server/application/Products/show/beverages,路由分析器會向頁面處理器傳入Products,show,beverages這些值。在這個例子中,如果使用server/application/{area}/{action}/{category}URL模式定義路由,頁面處理器將會收到一個字典集合,這個集合中包含以下鍵值對,area:Products,action:show,category:beverages。如果是在一個不被URL路由管理的請求中,/Products/show/beverages片斷將會被當作應用中的一個文件路徑解釋執行。
一、 路由[Routes]
路由是被處理程序映射的URL模式。處理程序可以是一個物理文件,例如Web Form應用中的.aspx文件。處理也可以是處理請求的類,例如MVC應用中的控制器。為了定義一個路由,你需要創建一個Route類的實例來指定URL模式,處理程序和可選的路由名稱。
你需要給RouteTable類的Routes靜態屬性添加Route對象來為應用添加路由。Routes屬性是一個RouteCollection對象,其中存放着應用中所有路由規則。
你通常沒有必要為MVC應用編寫代碼添加來添加路由規則。Visual Studio的MVC項目模板包含了預配置的URL路由規則。他們定義在MvcApplication類,這個類在Global.asax文件中。
二、 URL模式[URL Patterns]
一個URL模式可以包含字面值(literal)和可變的占位符(參考URL參數)。這些字面值和占位符在URL片斷中通過斜線(/)字符來分開和定位。
當一個請求到達,這個URL被解析成片斷和占位符,這些變量會提供給請求處理器。這個過程和將數據通過查詢字符串(query strings)中解析和傳輸至請求處理器很類似。這兩種情況下變量信息都會包含在URL中並傳到處理程序的鍵值對的表單中。對於查詢字符串而言,所有鍵(keys)和值(values)都包含在URL中。對於路由方式,所有鍵就是在URL模式中定義的占位符名稱,只有值包含中URL中。
在一個URL模式中,你定義的占位符被大括號包裹起來({and})。你可以在一個片斷中定義多個占位符,但是它們必須被字面值分隔開。例如,{language}-{country}/{action}就是一個合法的路由模式。然而{language}{country}/{action}不是一個合法的路由模式,因為它們的占位符之間缺少字面值或分隔符。因此,路由無法確定language和country占位符的值是何處分隔。
下表給出了合法的路由模式,以及其各自能正確匹配的URL請求。
路由定義 |
匹配URL示例 |
{controller}/{action}/{id} |
/Products/show/beverages |
{table}/Details.aspx |
/Products/Details.aspx |
blog/{action}/{entry} |
/blog/show/123 |
{reporttype}/{year}/{month}/{day} |
/sales/2008/1/5 |
{locale}/{action} |
/US/show |
{language}-{country}/{action} |
/en-US/show |
MVC應用中標准的URL模式[Typical URL Patterns in MVC Applications]
在MVC應用中,路由標准的URL模式包含{controller}和 {action}占位符。
當接收到一個請求時,它先被發送到UrlRoutingModule對象,再發送到MvcHandler HTTP處理程序。MvcHandler HTTP處理程序確定需要執行的控制器,通過給URL中的controller值添加”Controller”后綴從而確定將處理本次請求的控制器類型名稱。URL中的action值確定調用的處理方法。
例如,URL路徑 /Products會被映射成ProductsController控制器。action參數的值是被調用的處理方法的名稱。URL路徑/Products/show的映射結果將會是調用類ProductsController 的方法Show。
下表給出了默認的URL模式和它們能處理的URL請求示例。
默認URL模式 |
匹配URL示例 |
{controller}/{action}/{id} |
http://server/application/Products/show/beverages |
{resource}.axd/{*pathInfo} |
http://server/application/WebResource.axd?d=... |
路由使用模式 {resource}.axd/{*pathInfo} 來阻止對網絡文件的請求,例如WebReource.axd,ScriptResource.axd被傳遞給一個控制器。
對於IIS7.0,可以不用擴展名。對於IIS6.0,你必須將擴展名.mvc添加到URL模式,如下所示:{controller}.mvc/{action}/{id}
三、 為Web Forms應用程序添加路由[Add Routes to a Web Forms Application]
在Web Form應用中,你可以使用類RouteCollection的方法MapPageRoute(String, String, String) 創建路由。方法MapPageRoute創建Route對象並將其添加RouteCollection對象中。你需要為Route對象在參數在指定一些屬性,用來傳給方法MapPageRoute。
通常情況下,你在方法中添加的路由會被Global.asax文件中Application_Start 方法處理器調用。這種方法確保了這些路由在應用程序啟動時可以正常調用。它也允許你在為應用程序做單元測試時可直接調用該方法。當你在做單元測試時如果想要直接調用一個方法,該方法在注冊時就必須是靜態(Visual Basic中Shared)且有一個RouteCollection參數。
下例中演示了Global.asax文件中添加一個Route對象,該對象定義了action和categoryName兩個參數。URL中還定義了一個被定向到名為Categories.aspx的物理頁面。

protected void Application_Start(object sender, EventArgs e) { RegisterRoutes(RouteTable.Routes); } public static void RegisterRoutes(RouteCollection routes) { routes.MapPageRoute("", "Category/{action}/{categoryName}", "~/categoriespage.aspx"); }
四、 為MVC應用程序添加路由[Adding Routes to an MVC Application]
在MVC應用程序中,如果你采用MVC實現控制器的約定,即派生自類ControllerBase且以“Controller”結尾命名,那么你根本不需要搬運添加路由。預配置的路由將會執行你實現的控制器類中的處理方法。
如果你希望在MVC應用程序中添加自定義的路由,你可以使用方法MapRoute(RouteCollection, String, String) 來取代方法MapPageRoute(String, String, String)。
下面示例中演示在Global.asax文件中創建默認MVC路由的代碼,即是Visual Studio中MVC應用程序的項目模板。

public class MvcApplication : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" } // Parameter defaults ); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } }
五、 為URL參數設置默認值[Setting Default Values for URL Parameters]
當你定義一個路由時,你可以為參數指定一個默認值。如果一個參數的值不在URL中,則使用默認值。給路由設置默認值時是給類Route的屬性Defaults指定一個字典對象。下例演示了如何使用方法MapPageRoute(String, String, String, Boolean, RouteValueDictionary)添加一個包含默認值的路由。

void Application_Start(object sender, EventArgs e) { RegisterRoutes(RouteTable.Routes); } public static void RegisterRoutes(RouteCollection routes) { routes.MapPageRoute("", "Category/{action}/{categoryName}", "~/categoriespage.aspx", true, new RouteValueDictionary {{"categoryName", "food"}, {"action", "show"}}); }
下圖中演示了ASP.NET路由處理URL請求,路由定義(categoryName的默認值為food,action默認為show)和解析結果:
URL |
Parameter values |
/Category |
action = "show" (default value) categoryName = "food" (default value) |
/Category/add |
action = "add" categoryName = "food" (default value) |
/Category/add/beverages |
action = "add" categoryName= "beverages" |
對於MVC應用程序,方法RouteCollectionExtensions.MapRoute的重載版本,如MapRoute(RouteCollection, String, String, Object, Object),允許你指定默認值。
六、 URL模式中處理可變數量片斷[Handling a Variable Number of Segments in a URL Pattern]
有時候你必須處理包含可變個數的URL片斷的URL請求。當你定義一個路由時,你可以指定當一個URL擁有比模式中還要多的片斷時,額外的片斷會被當作最后一個片斷對待。你需要為最后一個參數添加一個星號(*)來用這種方式處理額外的片斷。這被稱作全匹配(catch-all)參數。包含全匹配參數也將匹配最后參數不帶任何值的URL。下例展示一個可以匹配無法確定片斷長度的路由模式。
query/{queryname}/{*queryvalues}
下圖中演示了ASP.NET路由處理URL請求,路由定義和解析結果。
URL |
Parameter values |
/query/select/bikes/onsale |
queryname = "select" queryvalues = "bikes/onsale" |
/query/select/bikes |
queryname = "select" queryvalues = "bikes" |
/query/select |
queryname = "select" queryvalues = Empty string |
七、 為路由添加約束[Adding Constraints to Routes]
路由模式中除了定義了可匹配URL請求的參數個數,還可以指定這些參數的值需要滿足的某些約束。如果一個URL中的參數值不符合一個路由的約束,那么此路由不會處理該請求。你添加的約束條件是為了確保URL參數中包含的值能在你的應用程序中工作。
約束條件是用正則表達式或實現了接口IRouteConstraint的對象來定義。當你將一條路由添加進Routes 集合時,你可以添加包含驗證測試的對象RouteValueDictionary約束條件。字典中的鍵唯一標識符合約束條件的參數。字典中的值既可以是符合正則表達式的字符串,也可以是實現接口IRouteConstraint的對象。
如果你提供一個字符串,路由會將它當作符合正則表達式的值,並調用Regex類的IsMatch()方法檢查該參數值是否符合規則。正則表達式總是不區分大小寫檢查。
如果你提供了一個IRouteConstraint對象,ASP.NET路由調用IRouteConstraint對象的Match()方法來檢查參數值是否合法。Match()方法返回布爾值來表明參數值是否合法。
下例中演示如何利用方法MapPageRoute 添加一條路由,並為參數locale和year添加約束。(MVC應用程序中,使用方法MapRoute。)

public static void RegisterRoutes(RouteCollection routes) { routes.MapPageRoute("", "Category/{action}/{categoryName}", "~/categoriespage.aspx", true, new RouteValueDictionary {{"categoryName", "food"}, {"action", "show"}}, new RouteValueDictionary {{"locale", "[a-z]{2}-[a-z]{2}"},{"year", @"\d{4}"}} ); }
當路由處理URL請求時,例子中路由的定義和解析后的結果如下表所示:
URL |
Result |
/US |
No match. Both locale and year are required. |
/US/08 |
No match. The constraint on year requires 4 digits. |
/US/2008 |
locale = "US" year = "2008" |
八、 路由不起作用的情況[Scenarios When Routing Is Not Applied]
在某些情況下,ASP.NET路由即使可用也不會處理請求。這節將介紹幾種路由不會處理請求的情況。
URL模式匹配一個有效的物理文件[A Physical File is Found that Matches the URL Pattern]
默認情況下,路由不會處理請求時,將其映射到Web服務器上一個已存在的物理文件。例如,如果存在一個物理文件Products/Beverages/Coffee.aspx,路由就不會處理請求http://server/application/Products/Beverages/Coffee.aspx。路由即使如下定義{controller}/{action}/{id},也能匹配該請求,它也不會處理該請求。
如果你希望路由能處理所有請求,即使請求指向一個文件,你可以通過設置對象RouteCollection的屬性RouteExistingFiles為true來重寫默認行為。當你將這個值設置為true則所有與定義路由模式匹配的請求都會被路由處理。
顯式禁用路由[Routing Is Explicitly Disabled for a URL Pattern]
你也可以指明路由不處理某些URL請求。定義一個路由並指明由類StopRoutingHandler處理該模式,以阻止路由處理某些請求。當一個請求被StopRoutingHandler對象處理時,StopRoutingHandler對象塊會為請求添加一些額外的信息。相反,這個請求會被當作一個ASP.NET頁面、Web服務或是其他ASP.NET終端處理。你可以使用方法RouteCollection.Ignore(MVC應用程序中RouteCollectionExtensions.IgnoreRoute)來創建使用類 StopRoutingHandler的路由。下面演示如何阻止對WebResource.axd文件的請求。

public static void RegisterRoutes(RouteCollection routes) { routes.Ignore("{resource}.axd/{*pathInfo}"); }
URL是如何被路由匹配的[How URLs Are Matched to Routes]
當路由開始處理URL請求時,它為嘗試着將請求匹配到一條路由規則上。一條路由規則能否匹配URL請求取決與以下條件:
-
- 在你的項目中是否包含自定義的路由規則或者默認路由。
- 集合Routes中添加路由規則的順序。
- 為路由規則添加的默認值。
- 為路由規則添加的約束。
- 是否定義了匹配對物理文件請求的路由。
為了避免不合適的路由處理了請求,在定義路由規則時一定要考慮所有這些條件。集合 Routes中Route對象出現的順序也應仔細思考。路由集合中從第一項到最后一項依次嘗試的路由匹配。當有一個匹配成功,不再對后續路由嘗試匹配。通常,添加路由時應先添加最具體的,最后添加最不明確的規則。
例如你添加了如下路由規則:
-
- 路由規則1,{controller}/{action}/{id}
- 路由規則2, products/show/{id}
路由2絕不會處理請求,因為路由1會最先嘗試匹配,並且與路由2匹配的請求在它上面也總是可以工作。例如請求http://server/application/products/show/bikes看起來好像和路由2更匹配,但是它會被路由1解析,解析結果如下:
-
- controller is products.
- action is show.
- id is bikes.
當請求的參數缺少時,默認值就能起作用。然而,它們可能會匹配到並非你所願的請求。例如,假如添加如下兩條路由規則:
-
- 路由1:{report}/{year}/{month},year,month帶有默認值。
- 路由2:{report}/{year},year有默認值。
路由2將絕無處理請求的機會。路由1希望能按月份匹配,而路由2則希望是按年度。但是,路由1中的默認值會讓所有匹配路由2的請求在路由1中也能工作。
你可以在路由中包含常量來避免這種歧義,例如annual/{report}/{year}和monthly/{report}/{year}/{month}。
如果一個URL不能匹配到在RouteTable集合中的任何一個Route對象,ASP.NET路由將不會處理該請求。
九、 從路由創建URL[Creating URLs from Routes]
如果你想要創建一個鏈接到你站點頁面的超鏈接,你可以使用URL模式編程創建符合路由的URL。當你修改了路由模式,URL會自動匹配到新的模式上。
十、 在路由頁面訪問URL參數[Accessing URL Parameters in a Routed Page]
參見:https://msdn.microsoft.com/en-us/library/dd535620.aspx
https://msdn.microsoft.com/en-us/library/dd394711.aspx
十一、 配置路由環境[Configuration Settings for Routing]
ASP.NET中,要讓應用程序支持路由功能,需要添加如下配置:

<configuration> <system.webServer> <modules runAllManagedModulesForAllRequests="true"> <!-- more --> </modules> </system.webServer> </configuration>
當runAllManagedModulesForAllRequests為true時,如下URLhttp://mysite/myapp/home,即使URL中沒有.aspx,.mvc或者其他擴展名,該請求也能到達ASP.NET。
然而,IIS7的更新導致不必添加配置項runAllManagedModulesForAllRequests,因為它本來就支持ASP.NET路由功能。
如果你的站點運行在IIS7且IIS已更新,你就不必設置該配置項為true。事實上,並不推薦設置它,因為它為所有請求增加了不必要的操作。如果設置該配置為true,所有請求,包括.htm,.jpg和其他靜態文件都會通過ASP.NET請求通道。
默認runAllManagedModulesForAllRequests為false。如果網站配置文件中沒有明確將其設置為true,而你又在未安裝SP1的Windows 7,不包含必要更新的IIS7中運行你的網站。 結果就是,你會看到路由不會工作的錯誤提示。如果路由中存在一些問題,你可以試試下面的方法:
-
- 將Windows 7更新到SP1,因為它添加了IIS7的更新。
- 安裝微軟件在先前文章中的描述的更新。
- 在Web.Config文件中設置runAllManagedModulesForAllRequests為true。注意這會添加一些額外開銷。
十二、 ASP.NET路由與安全性[ASP.NET Routing and Security]
授權規則可應用於單獨映射的路由URL或同時映射的路由URL和物理URL。例如,授權規則可以聲明所有用戶都可以訪問以開頭Category的URL,但是只有管理員才能訪問Categories.aspx頁面。如果路由URL模式contoso.com/Category/{controller}/{action} 映射到物理地址contoso.com/Categoriespage.aspx,你只能為路由地址添加授權規則,當用一個路由地址請求過之后,所有用戶都被允許可訪問Categoriespage.aspx。然而,當使用物理地址請求之后,只有管理才有權限訪問。
默認情況下,授權規則應用於路由地址和物理地址。
十三、 ASP.NET Web Form和路由安全性[ASP.NET Web Forms and Route Security]
在ASP.NET Web窗體應用程序中,你不應該將站點的安全性全寄托在路由授權規則,因為它們可能留下一些未保護處理的物理地址。
十四、 ASP.NET MVC和路由安全性[ASP.NET MVC and Route Security]
你不能使用路由或web.config文件保證MVC應用程序的安全性。唯一能保證MVC應用安全的做法是給所有控制器應用特性 AuthorizeAttribute ,並在登錄和注冊的方法(action)上應用特性AllowAnonymousAttribute 。
十五、 參考類[Class Reference]
Class |
Description |
Represents a route in a Web Forms or MVC application. |
|
Represents a route in a Dynamic Data application. |
|
Serves as the base class for all classes that represent an ASP.NET route. |
|
Stores the routes for an application. |
|
Provides methods that enable you to manage a collection of routes. |
|
Provides additional methods that enable you to manage a collection of routes in MVC applications. |
|
Contains the values for a requested route. |
|
Contains information about the HTTP request that corresponds to a route. |
|
Provides a way to specify that ASP.NET routing should not handle requests for a URL pattern. |
|
Provides a way to define routes for Web Forms applications. |
|
Provides a way to store route Constraints, Defaults, and DataTokensobjects. |
|
Provides a way to generate URLs from route information. |
十六、 ASP.NET路由VS URL重寫[ASP.NET Routing versus URL Rewriting]
ASP.NET路由與URL重寫不同。URL重寫方式處理到達的請求時,先修改其URL再將請求發送至Web頁面。例如,一個應用程序中可能使用URL重寫將/Products/Widgets/修改為/Products.aspx?id=4。同時,URL重寫的特點是沒有基於你的模式創建URL的API。使用URL重寫,如果你需要個性URL規則,你不得不手動更新所有相關聯的超鏈接。
使用ASP.NET路由,在處理到達的請求時URL不會發生變化,因為路由功能可能從URL中提取值。當你需要創建一個URL時,給一個方法傳入參數值就能為你生成URL。修改URL規則,只需要調整一個地方,你在應用程序中創建的所有鏈接都會自動使用新規則。