URL路由系統通過對請求地址進行解析從而得到以目標Controller名稱為核心的路由數據。Url路由系統最初是為了實現請求url與物理文件路徑分離而建立的,MVC的Url Route是將Url地址與物理文件映射轉移到了目標Controller的映射。
Url路由不是ASP.NET MVC特有的,而是建立在ASP.NET上面的,MVC的只是對這個路由的拓展使用(asp.net也開始使用這拓展了)。
我們在App_Start文件夾中找到RouteConfig.cs的文件,打開看
1 public static void RegisterRoutes(RouteCollection routes) 2 { 3 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 4 5 routes.MapRoute( 6 name: "Default", 7 url: "{controller}/{action}/{id}", 8 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 9 ); 10 }
大體可以猜出什么意思,url那一欄地址中第一個是controller,第二個是action,第三個是參數id,defaults是默認的參數,然后在Global.asax對該路由進行注冊。
1 protected void Application_Start() 2 { 3 AreaRegistration.RegisterAllAreas(); 4 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 5 RouteConfig.RegisterRoutes(RouteTable.Routes); 6 BundleConfig.RegisterBundles(BundleTable.Bundles); 7 }
簡單來說路由的任務:檢查請求的URL,找出當前請求的是哪個controller中的哪個action,並且有無帶了什么參數過來。
那好,我們來分析一下請求一個地址的時候,路由系統發生了什么事情?我們先來大膽的猜一下:類似於網絡設備的路由器,它會有一個路由表,根據我們配置的規則對端口過來的數據進行轉發,這張表里就記錄了匹配規則跟處理的程序,當一個數據包過來的時候,去這張表里面尋找所相應的發送地址,找到的話路由系統就將這數據包發往哪個對應的地址里面。
按照上面邏輯的話,我們先來找找匹配的規則在哪里加上來的,我們在上面的靜態方法里面看到有一個RouteCollection的東西,進去看看里面有啥?
發現了一個MapPageRoute的方法
1 // 2 // 摘要: 3 // 提供用於定義 Web 窗體應用程序的路由的方法。 4 // 5 // 參數: 6 // routeName: 7 // 路由的名稱。 8 // 9 // routeUrl: 10 // 路由的 URL 模式。 11 // 12 // physicalFile: 13 // 路由的物理 URL。 14 // 15 // 返回結果: 16 // 將添加到路由集合的路由。 17 public Route MapPageRoute(string routeName, string routeUrl, string physicalFile);
可以看到我們調用RouteCollection的MapPageRoute方法將某個物理文件路徑映射到一個URL模板上,這個過程其實就是基於指定的url模板創建一個路由對象,並且將他添加到這個全局路由表中,那程序是在哪里有個Add的入口呢?不小心在RouteCollection里面發現了一個Add的方法
1 // 摘要: 2 // 將路由添加到 System.Web.Routing.RouteCollection 對象的結尾,並為路由分配指定的名稱。 3 // 4 // 參數: 5 // name: 6 // 標識路由的值。 該值可為 null 或空字符串。 7 // 8 // item: 9 // 要添加到集合結尾的路由。 10 // 11 // 異常: 12 // System.ArgumentNullException: 13 // item 為 null。 14 // 15 // System.ArgumentException: 16 // name 已在集合中使用。 17 public void Add(string name, RouteBase item);
可以看到這里添加了一個Routebase的東西,我們點擊去看看是什么來頭?
1 // 摘要: 2 // 用作表示 ASP.NET 路由的所有類的基類。 3 [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")] 4 public abstract class RouteBase 5 { 6 // 摘要: 7 // 初始化該類供繼承的類實例使用。 此構造函數只能由繼承的類調用。 8 protected RouteBase(); 9 10 // 摘要: 11 // 獲取或設置一個值,該值指示 ASP.NET 路由操作是否應處理與現有文件匹配的 URL。 12 // 13 // 返回結果: 14 // 如果 ASP.NET 路由操作處理所有請求(甚至包括與現有文件匹配的請求),則為 true;否則為 false。 默認值為 false。 15 public bool RouteExistingFiles { get; set; } 16 17 // 摘要: 18 // 當在派生類中重寫時,會返回有關請求的路由信息。 19 // 20 // 參數: 21 // httpContext: 22 // 一個對象,封裝有關 HTTP 請求的信息。 23 // 24 // 返回結果: 25 // 一個對象,包含路由定義的值(如果該路由與當前請求匹配)或 null(如果該路由與請求不匹配)。 26 public abstract RouteData GetRouteData(HttpContextBase httpContext); 27 // 28 // 摘要: 29 // 當在派生類中重寫時,會檢查路由是否與指定值匹配,如果匹配,則生成一個 URL,然后檢索有關該路由的信息。 30 // 31 // 參數: 32 // requestContext: 33 // 一個對象,封裝有關所請求的路由的信息。 34 // 35 // values: 36 // 一個包含路由參數的對象。 37 // 38 // 返回結果: 39 // 一個對象(包含生成的 URL 和有關路由的信息)或 null(如果路由與 values 不匹配)。 40 public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values); 41 }
我們看到了兩個抽象方法:GetRouteData與GetVirtualPath,當一個請求過來的時候,它們都會去根據URL模板的模式與代表請求地址的URL地址進行匹配,如果匹配失敗返回null,成功的話,GetRouteData會得到一個封裝了路由信息的RouteData對象,而GetVirtualPath則會生成一個URL,該URL被封裝成VirtualPathData對象進行返回。
那通過以上猜測,我們知道了路由系統物理文件路徑添加到一個全局的路由表中,並傳入給定的參數調用同名方法去找到一個與指定請求URL相匹配的路由對象,並返回相應的RouteData和VirtualPathData對象。
好了,簡單的Url就寫就這里了,稍后會對下一步進行詳解,盡請期待!