這里我們就分享一些MVC框架原理上的東西,就從URL,路由機制等開始吧!關於MVC簡單的介紹大家可以去下載我分享的視頻或者自己去搜一些資料了解下,這就關於MVC基本介紹就不在羅嗦了!直接開始我們的URL路由部分。
簡介路由體系
MVC路由主要有兩個功能:
1. 檢查傳入的URL找出的對應的控制器(Controller)和方法(Action)請求。這就是MVC的路由體系處理我們客戶端請求的目的。
2. URL生成輸出。這些URL中出現的HTML渲染特定操作時將調用用戶單擊鏈接(此時,它已成為一個再次傳入的URL)。
我們開始創建一個項目("Routing"),用的是MVC應用程序是Internet Application模版。因為玩路由這些東東都在Global.asax文件里,所以在VS里打開該文件夾。默認的Global.asax文件如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace Routing { // 注意: 有關啟用 IIS6 或 IIS7 經典模式的說明, // 請訪問 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // 路由名稱 "{controller}/{action}/{id}", // 帶有參數的 URL new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 參數默認值 ); } protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); } } }
Application_Start方法由底層的Asp.Net當應用程序的平台第一次啟動時,使用RegisterRoutes方法注冊路由。該方法的參數是靜態RouteTable的屬性。這是RouteCollection類的一個實例。接下來我們刪除掉RegisterRoutes方法下的內容,因為我們要了解到他(URL模式)到底是怎么一回事,所以我們需要退一步,干掉這些默認(VS)自動創建的路由機制,用我們自己的配置來解開URL模式的真實面目。
簡介URL模式
路由系統的工作原理它的魔力,使用了一套路由。這些路由,集體撰寫的URL計划方案的應用程序,這是您的應用程序會識別和URL集回應。我們不需要手動輸入所有單獨的URL。相反,每個路由包含一個URL模式,這是比較傳入的URL。如果模式匹配的URL,那么它是用來處理URL路由系統(機制)。譬如在之前的項目實戰里,我們可以看到如下的URL:
Http://mysite.com/Admin/Index
這是我們用來訪問管理員的產品目錄的URL。URL可以分解成幾部分。這些URL的組成部分,不包括主機名和查詢字符串,被/字符。URL的例子中,有兩個部分,如下圖1.
圖1.第一部分包含Admin,第二部分包含Index。在我們眼里很明顯第一部分涉及到的控制器(Controller)和第二部分涉及的動作或者說方法(Action)。當然,我們需要這種關系來表達的方式,路由系統可以明白了,那到底URL模式是不是如下所:
{controller}/{action}
處理傳入的URL時,路由系統的工作是相匹配的URL模式,然后從URL中提取值段模式。段使用大括號({***}字符)表示變量。例如模式有兩個分部變量名controller(控制器)和 Action(方法)。
我們說匹配模式,MVC應用程序,因為通常都會有多條路由航線,路由機制會比較傳入的URL的各條路線的URL模式,直到它可以找到一個匹配。
默認情況下,一個URL模式將匹配任何URL正確數目的片段。對於示例,該示例將匹配任何模式的URL,有兩個部分,如下表所示
請求的URL | 細分變量 |
Http://mysite.com/Admin/Index | controller = Admin action =Index |
Http://mysite.com/Index/Admin | controller = Index action =Admin |
Http://mysite.com/Apples/Oranges | controller = Apples action = Oranges |
Http://mysite.com/Admin | 會報錯(段過少) |
Http://mysite.com/Admin/Index/Soccer | 會報錯(段過多) |
URL模式兩個突出的關鍵行為:
- URL模式是保守的,將匹配有相同的URL模式段的數量。
- URL模式是自由的。如果一個URL確實有正確的段數, 模式將提取的值段變量,不管怎樣。
這是默認的行為,這是了解URL模式運作的關鍵。
正如我們提到的,路由系統不知道任何關於MVC應用程序,這樣的匹配URL模式,即使是沒有控制器或動作對應的值提取從URL。你可以看到在表中的第二個例子證明了這一點。我們已調換在URL中的Admin和Index段,所以也一直從URL中提取的值調換。
創建和注冊一個簡單的路由
若你有了一個URL模式的思想,你可以使用它來定義一個路線。打開我們的Global.asax文件,注冊一個簡單的路由,具體如下:
public static void RegisterRoutes(RouteCollection routes) { Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); routes.Add("MyRoute", myRoute); }
這種方法是稍微更緊湊,主要是因為我們不需要創建一個實例MvcRouteHandler類。 MapRoutem方法是專為使用MVC應用程序。 ASP.NET網頁窗體應用程序可以使用的MapPageRoute方法在RouteCollection類定義。運行我們的程序,結果如下圖2.
圖2.
我們的URL模式已處理的URL,並提取控制器(Controller)變量的值和Action(方法)變量指數。 MVC框架要求的指標方法對我們來說,這是我們選擇了互聯網應用的MVC項目時創建的主控制器模板。
定義默認值
我們得到一個錯誤時,我們要求應用程序是默認URL的,它匹配我們定義不確定的路線相。默認URL表示為〜/路由系統,所以有沒有可以匹配的控制器和方法變量的分部。我們剛才解釋的URL模式是保守的,他們將配合的網址指定號碼段。我們也說,這是默認行為。改變這種情況的方法之一行為是使用默認值。默認值是當URL不包含段可以匹配的值。提供一個默認的路由具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); //提供默認路由 routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); }
作為一個匿名類型的屬性提供默認值。我們提供了一個指數的行動變量的默認值。這條航線將匹配所有兩部分的網址,現在,我們提供了默認值的動作段,路線也將匹配單段以及網址。處理URL時,路由系統將提取的控制器值從單一的URL部分,並用行動變量的默認值。這樣,我們可以要求的網址http://mydomain.com/Home和調用索引操作方法在主控制器的。運行結果如下圖3.
圖3.我們可以進一步定義不包含在所有的任何部分變量的URL,依托在剛剛 默認值來確定的行動和控制器。我們可以使用默認值的默認URL映射,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //提供方法和控制器默認值的路由 routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); }
通過定義提供方法和控制器的默認值的路由,我們可以直接訪問http://mysite即可,運行效果如下圖4.
圖4.提供控制器和操作變量的默認值,我們已經創造了一個路線將匹配具有變量段為零的地址,一個變量端或兩個變量段的部分,具體如下表:
段數 | 例子 | 映射 |
0 | mydomain.com | controller = Home action = Index |
1 | mydomain.com/Customer | controller = Customer action = Index |
2 | mydomain.com/Customer/List | controller = Customer action = Index |
3 | mydomain.com/Customer/List/All | (會報錯)段數過多 |
使用靜態URL段
並非所有URL模式的細分需要變量。你還可以創建模式靜態段。假設我們要匹配這樣的網址,支持前綴為公共的URL:
http://mydomain.com/Public/Home/Index
我們配置這樣一條模式,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //提供方法和控制器默認值的路由 routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); }
這將匹配URL模式包含三個部分,第一,必須是客戶的唯一地址。其他兩部分可以包含任何值,將用於控制器和行動變量。然后運行訪問我們Http://mysite/public/Home/Index,運行結果如下圖5.
圖5.
我們還可以創建URL模式,有段包含靜態和可變因素,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //提供方法和控制器默認值的路由 routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); }
在這條路線的模式匹配任何兩個分部的網址,其中第一部分開始字母X為控制器的開始,方法從第二部分。我們可以常識訪問下面的URL將匹配路由:
http://mydomain.com/XHome/Index ,運行結果如下圖6.
圖6.該URL將被定Home控制器上向到Action操作方法。
我們可以結合靜態URL段和默認值創建一個特定的URL別名。如果你已經公開發表您的URL模式,並形成了一個與用戶的合同可能是有用的。如果重構在這種情況下的應用程序,你需要保留以前的URL格式。打個比方吧!假如我們以前有一個Shop控制器,現在被Home控制器取代了我們如何才能創建一個路由維護舊的URL架構。我們可以用下面的辦法,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); //提供方法和控制器默認值的路由 routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); }
我們已經添加的路由匹配任何兩部分第一部分是Shop的URL。動作(Action)從第二個URL段值。 URL模式不包含的變量段控制器,所以我們提供的默認值使用。這意味着,(Action)動作上的要求被替代的控制器和現在控制器轉換。我們可以更近一步,創建動作(Action)方法重構也不再是在目前的別名控制器。要做到這一點,我們只需創建一個靜態的URL,並提供控制器和行動值默認值,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); //提供方法和控制器默認值的路由 routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); }
通知,我們首先應以我們新的路由。這是因為具體路由的遵循。如果Shop/ OldAction的要求下進行處理定義路由,例如,我們會得到一個不同的結果和我們想要的結果。該請求將被處理使用404 - Not Found錯誤頁面,而不是為了維護我們與用戶之間合約。
細分變量機制
我們不局限於只是控制器和行動變量。我們還可以定義自己的變量,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); //額外的變量定義URL模式 routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); }
路由的URL模式定義典型的控制器和(Action)動作變量,以及自定義變量名為id。這條路由將匹配任何零到三段的URL。第三內容段將被分配到id變量,如果沒有第三部分,則默認值將是使用。我們可以使用RouteData.Values訪問任何分部變量在操作方法屬性。為了證明這一點,我們添加了一個方法在HomeController,在主控制器類叫做CustomVariable,具體代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace Routing.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "歡迎使用 ASP.NET MVC!"; return View(); } public ViewResult CustomVariable() { this.ViewBag.CustomVariable = RouteData.Values["id"]; return this.View(); } public ActionResult About() { return View(); } } }
我們添加相應的視圖,具體代碼如下:
@{ ViewBag.Title = "CustomVariable"; } <h2>Variable: @ViewBag.CustomVariable</h2>
如果您運行的應用程序瀏覽URL/Home/ CustomVariable/Hello,CustomVariable的在HomeController的方法被稱為動作方法,自定義部分變量的值被檢索從ViewBag和顯示出來,結果如下圖7.
圖7.
使用自定義變量作為參數的操作方法
使用RouteData.Values屬性,只有一個辦法來訪問自定義路由變量。另一種方法是更優雅。如果我們定義的參數名稱與我們的操作方法相匹配的網址模式變量,MVC框架將通過從URL作為參數的操作方法獲得的值。例如,自定義變量,在我們上面的路由被稱為ID。我們可以修改的CustomVariable的操作方法,因此,它有一個匹配的參數,具體代碼如下:
//映射一個自定義URL段變量來一個動作方法參數 public ViewResult CustomVariable(string id ) { this.ViewBag.CustomVariable = this.Index(); return this.View(); }
當路由系統匹配對我們在我們配置的路由表定義的URL網址,價值在URL中的第三部分是分配給自定義變量的指數。 MVC框架的比較段與操作方法的參數列表變量列表,如果匹配的名字,通過從URL值的方法。我們已經定義了id參數為一個字符串,但MVC框架將嘗試轉換網址值到任何參數類型定義。如果我們宣布id參數為一個int或一個DateTime,然后,我們將收到從解析托安該類型的實例的URL值。這是一個優雅有用的功能,不再需要我們自己處理的轉換。
定義可選的URL片段
一個可選的URL部分是一個用戶不需要指定,但其中沒有默認值是規定。我們指定段的變量是可選的設置默認值UrlParameter.Optional,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); //指定一個可選的URL片段 routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); }
這條路由將匹配與否的ID段已提供的網址.下表描述這種路由用於不同的URL。(用一個可選的部分匹配url變量)
段數 | 例子 | 映射 |
0 | mydomain.com | controller= Home action= Index |
1 | mydomain.com/Customer | controller= Customer action= Index |
2 | mydomain.com/Customer/List | controller= Customer action= List |
3 | mydomain.com/Customer/List/All | controller= Customer action= List id = All |
4 | mydomain.com/Customer/List/All/Delete | 會報錯(段數過多) |
正如你可以看到其外表,只有當有一個id變量被添加到組變量傳入URL中的相應部分。要清楚,這不是id值是空的時,沒有提供相應的段;相反,情況是,一個id變量沒有被定義。如果你需要知道用戶是否提供了有價值的東東,此功能非常有用。如果我們提供了一個id參數的默認值的操作方法,並獲得該值,我們將無法告訴如果使用默認值或用戶正好請求的URL中的默認值。可選段的一個常見的用途是強制執行的關注點分離,這樣的默認值操作方法參數不包含在路由定義。如果你想按照此實踐中,你可以使用的C#可選參數功能來定義你的操作方法參數,具體如下:
//定義一個默認值為一個動作方法參數 public ViewResult CustomVariable(string id = "DefaultId") { this.ViewBag.CustomVariable = id; return this.View(); }
運行,結果如下圖8.
圖8.
定義變長的路由
改變URL模式的默認保守的另一種方法是接受可變數目的URL段。這可以讓你任意長度在一個單一的路由,路由網址。您定義的支持做前綴的變量段指定段作為一個包含所有的變量之一,星號(*)。具體實例一個路由如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //指定一個包括所有變量的路由 routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); }
我們變成路由,從前面的例子添加一個包括所有的細分變量,這是我們想象的包括所有的變量。現在,這條路由將匹配任何URL。前三段值,分別為控制器,動作和id變量。如果URL中包含額外段,他們都被分配到我們的包括有意變量段(也就是{*catchall})部分。這條路由可以匹配的URL如下表:
段數 | 例子 | 映射 |
0 | mydomain.com | controller= Home action= Index |
1 | mydomain.com/Customer | controller= Customer action= Index |
2 | mydomain.com/Customer/List | controller= Customer action= List |
3 | mydomain.com/Customer/List/All | controller= Customer action= List id = All |
4 | mydomain.com/Customer/List/All/Delete | controller= Customer action= List id = All catchall = Delete |
5 | mydomain.com/Customer/List/All/Delete/Perm | controller= Customer action= List id = All catchall = Delete/Perm |
有段,在這條路線的URL模式匹配的數量沒有上限。請注意,段由包擴所有捕獲的形式段/段/段。我們是負責處理字符串打破了個別分部。
優先控制器名稱空間
當傳入的URL匹配的路由,MVC框架的控制器變量的值尋找適當的名稱。例如,當控制器變量的值是Home,然后看起來HomeController控制器的MVC框架。這是一個不合格的類名,這意味着,MVC框架並不知道怎么做,如果有兩個或兩個以上的類稱為HomeController在不同的命名空間。當發生這種情況,將報告一個錯誤,如下圖9:
圖9.(你可以給項目在加一個HomeController)試試。
這個問題時,往往比較常見,特別是如果你在一個大的MVC工作從其他的開發團隊或第三方供應商的控制器使用庫的項目。這是自然命名有關用戶帳戶的AccountController例如,一個控制器,它僅僅是一個時間的問題之前,你遇到命名沖突。為了解決這個問題,我們可以告訴MVC框架,優先某些命名空間當試圖解決的一個控制器類的名稱,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定一個包括所有變的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //指定名稱空間解析順序 routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers" }); }
我們作為一個字符串數組表示的命名空間。在程序運行后,我們已經告訴MVC框架看在URLsAndRoutes.Controllers命名空間之前,尋找到別的地方去。如果有合適的控制器不能被發現在該命名空間,然后將默認的MVC框架到其正常的行為,並看在所有可用的命名空間。名稱空間添加到路線都具有同等的優先級。 MVC框架不檢查第一個命名空間,然后再移動到第二等等。例如,假設我們添加了兩個我們的項目命名空間的路線,代碼如下面:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定一個包括所有變的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //指定名稱空間解析順序 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers" }); routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers", "AdditionalControllers" }); }
我們會看到如上圖8同樣的錯誤,因為MVC框架試圖解決路由添加到命名空間,我們所有的控制器類的名稱。如果我們想給優先在一個命名空間的單個控制器,但在另一個解決所在其他控制器命名空間,我們需要創建多條路由,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定一個包括所有變的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //指定名稱空間解析順序 routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers" }); //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers", "AdditionalControllers" }); //使用多個路由控制名稱空間解析 routes.MapRoute("AddContollerRoute", "Home/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "AdditionalControllers" }); }
我們可以告訴MVC框架,只是看在我們指定的命名空間。如果一個匹配控制器不能被發現,然后框架將不會尋找其他地方。具體如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定一個包括所有變的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定名稱空間解析順序 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers" }); //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers", "AdditionalControllers" }); ////使用多個路由控制名稱空間解析 //routes.MapRoute("AddContollerRoute", "Home/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "AdditionalControllers" }); //禁止依靠其他的命名空間 Route myRoute = routes.MapRoute("AddControllerRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); myRoute.DataTokens["UseNamespaceFallback"] = false; }
MapRoute方法返回一個Route對象。我們一直忽略在前面的例子,因為我們並不需要作出任何調整所創建的路線。要禁用搜索其他命名空間中的控制器,我們必須采取Route對象,並設置UseNamespaceFallback鍵的DataTokens集合屬性為false。此設置將被傳遞給組件負責尋找控制器詳細的后續在學習。
約束路由
我們描述了如何URL模式是保守他們如何匹配段和自由的他們是如何匹配的段的內容。前面已經解釋保守主義控制的程度不同的技術(或許有些地方描述的不清錯好着錯誤還請大家指教)路由符合更多或更少段使用默認值,可選的變量,依此類推。現在是時候來看看我們如何能夠控制自由主義的匹配URL內容段如何限制的路由將匹配一組URL。一旦我們有控制權路由的行為,這些方面,我們可以創建URL表示的很精確。
約束路由使用一個正則表達式
我們看看如何使用正則表達式來約束路由,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定一個包括所有變的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定名稱空間解析順序 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers" }); //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers", "AdditionalControllers" }); ////使用多個路由控制名稱空間解析 //routes.MapRoute("AddContollerRoute", "Home/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "AdditionalControllers" }); ////禁止依靠其他的命名空間 //Route myRoute = routes.MapRoute("AddControllerRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //myRoute.DataTokens["UseNamespaceFallback"] = false; //約束路由使用一個正則表達式 routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new { controller = "^H.*" }, new[] { "URLsAndRoutes.Controllers"}); }
我們通過MapRoute方法的參數定義約束。默認值一樣,作為一個匿名類型,其中類型的屬性對應的約束表示我們要約束段變量的名稱。在這個例子中,我們用一個正則表達式匹配的URL只有在約束控制器變量的值開始字母H。
限制一個路由到一組特定的值
我們可以使用正則表達式限制路線,充分使用,只有特定的URL段值導致匹配。我們做到這一點使用豎線(|)字符,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定一個包括所有變的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定名稱空間解析順序 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers" }); //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers", "AdditionalControllers" }); ////使用多個路由控制名稱空間解析 //routes.MapRoute("AddContollerRoute", "Home/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "AdditionalControllers" }); ////禁止依靠其他的命名空間 //Route myRoute = routes.MapRoute("AddControllerRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //myRoute.DataTokens["UseNamespaceFallback"] = false; ////約束路由使用一個正則表達式 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new { controller = "^H.*" }, // new[] { "URLsAndRoutes.Controllers"}); //約束路由一個分部變量值的一組特定 routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new { controller = "^H.*", action = "^Index$|^About$" }, new[] { "URLsAndRoutes.Controllers" }); }
這個約束將允許路由,以配合關於行動部分的值是唯一網址。約束被應用於在一起,這樣的值的行動所施加的限制變量結合所施加的控制器上的變量。這意味着,只有當控制器變量一方面開始匹配動作變量匹配網址。所以,現在你可以看到,我們創造非常精確的路由。
限制使用HTTP方法的路由
我們可以限制路線,使它們匹配URL,只有當它使用一個特定的HTTP請求法,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定一個包括所有變的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定名稱空間解析順序 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers" }); //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers", "AdditionalControllers" }); ////使用多個路由控制名稱空間解析 //routes.MapRoute("AddContollerRoute", "Home/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "AdditionalControllers" }); ////禁止依靠其他的命名空間 //Route myRoute = routes.MapRoute("AddControllerRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //myRoute.DataTokens["UseNamespaceFallback"] = false; ////約束路由使用一個正則表達式 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new { controller = "^H.*" }, // new[] { "URLsAndRoutes.Controllers"}); ////約束路由一個分部變量值的一組特定 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new { controller = "^H.*", action = "^Index$|^About$" }, // new[] { "URLsAndRoutes.Controllers" }); //基於約束路由HTTP方法 routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new { controller = "^H.*", action = "Index|About" , httpMethod = new HttpMethodConstraint("GET")}, new[] { "URLsAndRoutes.Controllers" }); }
指定HTTP方法約束的格式是有點奇怪。不要緊,叫什么名字我們給出屬性,只要我們分配的的HttpMethod約束類的實例,我們稱之為我們的約束屬性httpMethod,以幫助區分它的價值為基礎的限制。我們通過HTTP方法的名稱,我們要支持字符串參數的構造HttpMethod約束類。而且限制了路由GetRequests要求,但我們可以有容易添加其他方法的支持,具體如下:
... httpMethod = new HttpMethodConstraint("GET", "POST") }, ...
定義一個自定義約束
如果標准的約束不能滿足你的需求,您可以定義您自己的自定義約束通過實現IRouteConstraint接口(給項目添加一個來定義類),具體代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Routing; namespace Routing.Infrastructure { public class UserAgentConstraint : IRouteConstraint { private string requiredUserAgent; public UserAgentConstraint(string agentParam) { this.requiredUserAgent = agentParam; } public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { return httpContext.Request.UserAgent != null && httpContext.Request.UserAgent.Contains(this.requiredUserAgent); } } }
IRouteConstraint接口定義一個實現可以使用Match方法,顯示路由系統,如果它的約束條件已得到滿足。匹配方法的參數提供訪問請求從客戶端,正在評估的路線,參數名稱的約束,該段從URL中提取的變量,並請求是否是細節檢查傳入或傳出的URL。對於我們的例子中,我們檢查的UserAgent屬性值客戶端的請求,看它是否包含一個值傳遞給我們的構造。下面顯示了我們自定義約束的路由,具體配置如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定一個包括所有變的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定名稱空間解析順序 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers" }); //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers", "AdditionalControllers" }); ////使用多個路由控制名稱空間解析 //routes.MapRoute("AddContollerRoute", "Home/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "AdditionalControllers" }); ////禁止依靠其他的命名空間 //Route myRoute = routes.MapRoute("AddControllerRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //myRoute.DataTokens["UseNamespaceFallback"] = false; ////約束路由使用一個正則表達式 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new { controller = "^H.*" }, // new[] { "URLsAndRoutes.Controllers"}); ////約束路由一個分部變量值的一組特定 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new { controller = "^H.*", action = "^Index$|^About$" }, // new[] { "URLsAndRoutes.Controllers" }); ////基於約束路由HTTP方法 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new // { // controller = "^H.*", // action = "Index|About", // httpMethod = new HttpMethodConstraint("GET") // }, // new[] { "URLsAndRoutes.Controllers" }); //應用自定義約束的路由 routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new { controller = "^H.*", action = "Index|About", httpMethod = new HttpMethodConstraint("GET", "POST"), customConstraint = new UserAgentConstraint("IE") }, new[] { "URLsAndRoutes.Controllers" }); }
我們已經限制了路由,這樣它會匹配來自瀏覽器的唯一請求其用戶代理字符串包含IE瀏覽器,其中包括來自微軟瀏覽器的請求。
路由請求磁盤文件
不是所有MVC應用程序的要求是控制器和行動。我們仍然需要以服務的方式內容,如圖像,靜態HTML文件,JavaScript庫,等等。作為例子,我們有創建一個文件稱為StaticContent.html在我們的例子MVC應用程序的內容文件夾。StaticContent.html代碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Static HTML Content</title> </head> <body> This is the static html file (~/Content/StaticContent.html) </body> </html>
路由系統提供集成支持服務等內容。如果您啟動應用程序請求的URL/Content/StaticContent.html的,你會看到這個簡單的HTML文件的內容顯示在瀏覽器如下圖9所示。
圖9.
默認情況下,路由系統的檢查,看看如果URL匹配磁盤文件前評估應用程序的路由。然后在磁盤上的文件送達,從來沒有使用過的路由。我們可以扭轉這一行為,使我們的路由是評估前檢查磁盤上的文件通過設置RouteExistingFiles屬性RouteCollection為true,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定一個包括所有變的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定名稱空間解析順序 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers" }); //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers", "AdditionalControllers" }); ////使用多個路由控制名稱空間解析 //routes.MapRoute("AddContollerRoute", "Home/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "AdditionalControllers" }); ////禁止依靠其他的命名空間 //Route myRoute = routes.MapRoute("AddControllerRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //myRoute.DataTokens["UseNamespaceFallback"] = false; ////約束路由使用一個正則表達式 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new { controller = "^H.*" }, // new[] { "URLsAndRoutes.Controllers"}); ////約束路由一個分部變量值的一組特定 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new { controller = "^H.*", action = "^Index$|^About$" }, // new[] { "URLsAndRoutes.Controllers" }); ////基於約束路由HTTP方法 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new // { // controller = "^H.*", // action = "Index|About", // httpMethod = new HttpMethodConstraint("GET") // }, // new[] { "URLsAndRoutes.Controllers" }); ////應用自定義約束的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", // new { controller = "Home", action = "Index", id = UrlParameter.Optional }, //new //{ // controller = "^H.*", // action = "Index|About", // httpMethod = new HttpMethodConstraint("GET", "POST"), // customConstraint = new UserAgentConstraint("IE") //}, //new[] { "URLsAndRoutes.Controllers" }); //啟用路由之前評估文件檢查 routes.RouteExistingFiles = true; routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new { controller = "^H.*", action = "Index|About", httpMethod = new HttpMethodConstraint("GET", "POST"), customConstraint = new UserAgentConstraint("IE") }, new[] { "URLsAndRoutes.Controllers" }); }
該公約是把這個聲明保持着密切的RegisterRoutes方法,雖然它將生效,即使你把它設置后,您已經定義了的路由。一旦屬性已設置為true,我們可以定義匹配的URL對應的磁盤文件的路由,具體代碼如下:
public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定一個包括所有變的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定名稱空間解析順序 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers" }); //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers", "AdditionalControllers" }); ////使用多個路由控制名稱空間解析 //routes.MapRoute("AddContollerRoute", "Home/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "AdditionalControllers" }); ////禁止依靠其他的命名空間 //Route myRoute = routes.MapRoute("AddControllerRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //myRoute.DataTokens["UseNamespaceFallback"] = false; ////約束路由使用一個正則表達式 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new { controller = "^H.*" }, // new[] { "URLsAndRoutes.Controllers"}); ////約束路由一個分部變量值的一組特定 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new { controller = "^H.*", action = "^Index$|^About$" }, // new[] { "URLsAndRoutes.Controllers" }); ////基於約束路由HTTP方法 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new // { // controller = "^H.*", // action = "Index|About", // httpMethod = new HttpMethodConstraint("GET") // }, // new[] { "URLsAndRoutes.Controllers" }); ////應用自定義約束的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", // new { controller = "Home", action = "Index", id = UrlParameter.Optional }, //new //{ // controller = "^H.*", // action = "Index|About", // httpMethod = new HttpMethodConstraint("GET", "POST"), // customConstraint = new UserAgentConstraint("IE") //}, //new[] { "URLsAndRoutes.Controllers" }); ////啟用路由之前評估文件檢查 //routes.RouteExistingFiles = true; //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", // new { controller = "Home", action = "Index", id = UrlParameter.Optional }, //new //{ // controller = "^H.*", // action = "Index|About", // httpMethod = new HttpMethodConstraint("GET", "POST"), // customConstraint = new UserAgentConstraint("IE") //}, //new[] { "URLsAndRoutes.Controllers" }); //一個路由的URL模式對應於一個磁盤文件 routes.RouteExistingFiles = true; routes.MapRoute("DiskFile", "Content/StaticContent.html", new { controller = "Account", action = "LogOn" }, new { customConstraint = new UserAgentConstraint("IE") }); routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new { controller = "^H.*", action = "Index|About", httpMethod = new HttpMethodConstraint("GET", "POST"), customConstraint = new UserAgentConstraint("IE") }, new[] { "URLsAndRoutes.Controllers" }); }
這條路由映射請求的URL Content/StaticContent.html的登錄動作帳戶控制器。我們增加了一個約束的路由,這意味着它只會匹配從瀏覽器的用戶代理字符串的請求。
當RouteExistingFiles屬性已啟用磁盤上的文件將只提供給客戶,如果有有匹配的路由請求。對於我們的例子路由,這意味着IE瀏覽器的用戶將從Account控制器的響應,雖然所有其他用戶將看到的靜態內容。運行如下圖10。
圖10.
回避路由機制
設置的RouteExistingFiles屬性,這是我們在上面展示,使得路由機制更具包容性。現在我們需要會繞過路由機制評估對我們定義的路由此功能相對應的是能力,使路由機制的包容性和防止URL從回避我們正在評估對路由。為此,我們使用的IgnoreRoute方法在RouteCollection類。具體代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; using Routing.Infrastructure; namespace Routing { // 注意: 有關啟用 IIS6 或 IIS7 經典模式的說明, // 請訪問 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } public static void RegisterRoutes(RouteCollection routes) { //Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); //routes.Add("MyRoute", myRoute); ////提供默認路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" }); //別名的一個控制器和一個方法 routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" }); //混合靜態URL段和默認值 routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" }); //配置混合段的URL模式 routes.MapRoute("", "X{controller}/{action}"); ////提供方法和控制器默認值的路由 //routes.MapRoute("MyRoute", "{controller}/{action}", new { controller = "Home", action = "Index" }); //配置靜態段的URL模式 routes.MapRoute("", "Public/{controller}/{action}", new { controller = "Home", action = "Index" }); ////額外的變量定義URL模式 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); ////指定一個可選的URL片段 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定一個包括所有變的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); ////指定名稱空間解析順序 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers" }); //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "URLsAndRoutes.Controllers", "AdditionalControllers" }); ////使用多個路由控制名稱空間解析 //routes.MapRoute("AddContollerRoute", "Home/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "AdditionalControllers" }); ////禁止依靠其他的命名空間 //Route myRoute = routes.MapRoute("AddControllerRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //myRoute.DataTokens["UseNamespaceFallback"] = false; ////約束路由使用一個正則表達式 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new { controller = "^H.*" }, // new[] { "URLsAndRoutes.Controllers"}); ////約束路由一個分部變量值的一組特定 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new { controller = "^H.*", action = "^Index$|^About$" }, // new[] { "URLsAndRoutes.Controllers" }); ////基於約束路由HTTP方法 //routes.MapRoute("MyRoute", "Home/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // new // { // controller = "^H.*", // action = "Index|About", // httpMethod = new HttpMethodConstraint("GET") // }, // new[] { "URLsAndRoutes.Controllers" }); ////應用自定義約束的路由 //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", // new { controller = "Home", action = "Index", id = UrlParameter.Optional }, //new //{ // controller = "^H.*", // action = "Index|About", // httpMethod = new HttpMethodConstraint("GET", "POST"), // customConstraint = new UserAgentConstraint("IE") //}, //new[] { "URLsAndRoutes.Controllers" }); ////啟用路由之前評估文件檢查 //routes.RouteExistingFiles = true; //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", // new { controller = "Home", action = "Index", id = UrlParameter.Optional }, //new //{ // controller = "^H.*", // action = "Index|About", // httpMethod = new HttpMethodConstraint("GET", "POST"), // customConstraint = new UserAgentConstraint("IE") //}, //new[] { "URLsAndRoutes.Controllers" }); ////一個路由的URL模式對應於一個磁盤文件 //routes.RouteExistingFiles = true; //routes.MapRoute("DiskFile", "Content/StaticContent.html", new { controller = "Account", action = "LogOn" }, // new { customConstraint = new UserAgentConstraint("IE") }); //routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", // new { controller = "Home", action = "Index", id = UrlParameter.Optional }, //new //{ // controller = "^H.*", // action = "Index|About", // httpMethod = new HttpMethodConstraint("GET", "POST"), // customConstraint = new UserAgentConstraint("IE") //}, //new[] { "URLsAndRoutes.Controllers" }); //使用IgnoreRoute方法 routes.RouteExistingFiles = true; routes.MapRoute("DiskFile", "Content/StaticContent.html", new { controller = "Account", action = "LogOn" }, new { customConstraint = new UserAgentConstraint("IE") }); //忽略給定路由表約束列表指定的URL routes.IgnoreRoute("Content/{filename}.html"); routes.MapRoute("", "{controller}/{action}"); routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new { controller = "^H.*", action = "Index|About", httpMethod = new HttpMethodConstraint("GET", "POST"), customConstraint = new UserAgentConstraint("IE") }, new[] { "URLsAndRoutes.Controllers" }); }protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); } } }
我們可以使用像{filename}的部分變量的URL匹配的范圍。在這種情況下,URL模式將匹配任何兩部分,第一部分是內容的URL和第二個內容.html擴展。IgnoreRoute方法創建條目,其中的路由處理程序是在RouteCollection實例的StopRoutingHandler類,而不是MvcRouteHandler。路由系統是硬編碼的,以識別這個處理程序。如果URL傳遞給IgnoreRoute模式匹配方法,然后沒有路由將被評估,就像當一個普通的路由匹配時。因此,我們把調用IgnoreRoute方法的看是重要的. OK關於路由這里先分享一到這里,感覺路由這東西還是挺大的,分享的話貌似還有好多東西。文章寫的長,估計也有描述不正確或者錯誤的地方,還請路過的前輩們多多指教,大家共同學習。謝謝!