1. 程式人生 > >ASP.NET MVC路由擴充套件:路由對映

ASP.NET MVC路由擴充套件:路由對映

上週我寫了三篇文章()詳細地介紹了ASP.NET的路由系統。ASP.NET的路由系統旨在通過註冊URL模板與物理檔案之間的對映進而實現請求地址與檔案路徑之間的分離,但是對於ASP.NET MVC應用來說,請求的目標不再是一個具體的物理檔案,而是定義在某個Controller型別中的Action方法。出於自身路由特點的需要,ASP.NET對ASP.NET的路由系統進行了相應的擴充套件。

目錄
一、基本路由對映
二、例項演示:註冊路由對映與檢視路由資訊
三、基於Area的路由對映
    1、AreaRegistration與AreaRegistrationContext 
    2、AreaRegistration的快取


    3、例項演示:檢視基於Area路由資訊

一、基本路由對映

通過前面的介紹我們知道基於某個物理檔案的路由對映通過呼叫代表全域性路由表的RouteTable的靜態屬性Routes(一個RouteCollection物件)的MapPageRoute方法來完成,為了實現針對目標Controller和Action的路由,ASP.NET MVC針對RouteCollection型別定義了一系列的擴充套件方法以實現檔案路徑無關的路由對映,這些擴充套件方法定義在RouteCollectionExtensions型別中。如下面的程式碼片斷所示,RouteCollectionExtensions定義了兩組方法,方法IgnoreRoute用於註冊不需要進行路由的URL模板,對應於RouteCollectionExtensions的Ignore方法;彷彿MapRoute用於進行基於URL模板的路由註冊,對應於RouteCollectionExtensions的MapPageRoute方法。

   1: public static class RouteCollectionExtensions
   2: {
   3:     //其他成員   
   4:     public static void IgnoreRoute(this RouteCollection routes, string url);    
   5:     public static void IgnoreRoute(this RouteCollection routes, string url, object constraints);   
   6:  
   7:     public static Route MapRoute(this RouteCollection routes, string name, string url);    
   8:     public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults);    
   9:     public static Route MapRoute(this RouteCollection routes, string name, string url, string[] namespaces);    
  10:     public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints);    
  11:     public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces);    
  12:     public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces);
  13: }

由於ASP.NET MVC的路由註冊與具體的物理檔案無關,所以MapRoute方法中並沒有一個表示檔案路徑的physicalFile引數。與直接定義在RouteCollectionExtensions中的Ignore和MapPageRoute方法不同的是,表示預設變數的引數defaults和基於正則表示式的變數約束的引數constraints都不再是一個RouteValueDictionary物件,而是一個普通的object。這主要是為了程式設計上的便利,使得我們可以通過匿名型別的方式來指定這兩個引數值。該方法在內部會通過反射的方式得到指定物件所有屬性值,並轉換為RouteValueDictionary物件,其屬性名和屬性值作為字典元素的Key和Value。

對於ASP.NET MVC來說,最終需要通過在請求地址中指定的Controller名稱來建立具體的Controller例項。由於Controller名稱 僅僅對應著型別的名稱,Controller的成功例項化的前提是我們能夠正確地解析出它的具體型別,所以我們需要使用了名稱空間。在呼叫MapRoute方法的時候我們可以通過字串陣列型別的引數namespaces來指定一個名稱空間的列表。對於註冊的名稱空間,可以指定一個代表完整名稱空間的字串,也可以使用“*”作為萬用字元。

新增的命名控制元件列表最終是被儲存於Route物件的DataTokens屬性中,對應的Key為“Namespaces”。MapRoute方法沒有為初始化Route物件的DataTokens屬性提供相應的引數,如果沒有指定名稱空間列表,所有通過該方法新增的Route物件的DataTokens屬性總是一個空的RouteValueDictionary物件。

對於針對定義在某個Controller中的某個Action的請求,如果註冊的路由表與之匹配,具體匹配的某個路由物件的GetRouteData被呼叫並返回一個具體的RouteData物件。根據對請求地址進行解析得到的目標Controller和Action的名稱必須包含在該RouteData的Values屬性對應的RouteValueDictionary物件中,其對應的Key分別為controlleraction

二、 例項演示:註冊路由對映與檢視路由資訊

ASP.NET MVC通過定義在RouteCollectionExtensions中的擴充套件方法MapRoute進行路由對映,為了讓讀者對此有一個深刻的認識,我們來進行一個簡單的例項演示。我們依然沿用之前關於獲取天氣資訊的場景,看看通過這種方式進行註冊的Route物件針對匹配的HTTP請求返回怎樣的RouteData物件。[原始碼從這裡下載]

我們在建立的ASP.NET Web應用(不是ASP.NET MVC應用)新增一個Web頁面(Default.aspx),並按照之前的方式以內聯程式碼的方式直接將RouteData的相關屬性顯示出來,頁面主體部分的HTML如下所示。需要注意的是我們顯示的RouteData是從定義的方法GetRouteData方法獲取的,而不是對應於當前頁面的RouteData屬性。

   1: <body>
   2:     <form id="form1" runat="server">
   3:     <div>
   4:         <table>
   5:             <tr>
   6:                 <td>Route:</td>
   7:                 <td><%=GetRouteData().Route != null? GetRouteData().Route.GetType().FullName:"" %></td>
   8:             </tr>
   9:             <tr>
  10:                 <td>RouteHandler:</td>
  11:                 <td><%=GetRouteData().RouteHandler != null? GetRouteData().RouteHandler.GetType().FullName:"" %></td>
  12:             </tr>
  13:             <tr>
  14:                 <td>Values:</td>
  15:                 <td>
  16:                     <ul>
  17:                         <%foreach (var variable in GetRouteData().Values)
  18:                           {%>
  19:                         <li><%=variable.Key%>=<%=variable.Value%></li>
  20:                         <% }%>
  21:                     </ul>
  22:                 </td>
  23:             </tr>
  24:             <tr>
  25:                 <td>DataTokens:</td>
  26:                 <td>
  27:                     <ul>
  28:                         <%foreach (var variable in GetRouteData().DataTokens)
  29:                           {%>
  30:                         <li><%=variable.Key%>=<%=variable.Value%></li>
  31:                         <% }%>
  32:                     </ul>
  33:                 </td>
  34:             </tr>
  35:         </table>
  36:     </div>
  37:     </form>
  38: </body>

我們將GetRouteData方法定義在當前頁面的後臺程式碼中。如下面的程式碼片斷所示,我們手工建立了一個HttpRequest和HttpResponse物件,HttpRequest的請求的地址為“http://localhost:3721/0512/3”(3721是本Web應用對應的埠號)。根據這兩個物件建立了HttpContext物件,並以此建立一個HttpContextWrapper物件。最終我們將其作為引數呼叫RouteTable的Routes屬性的GetRouteData方法並返回。這個方法實際上就是模擬註冊的路由錶針對相對地址為“/0512/3”的HTTP請求的路由處理。

   1: public partial class Default : System.Web.UI.Page
   2: {
   3:     private RouteData routeData;
   4:     public RouteData GetRouteData()
   5:     {
   6:         if (null != routeData)
   7:         {
   8:             return routeData;
   9:         }
  10:         HttpRequest request = new HttpRequest("default.aspx", "http://localhost:3721/0512/3", null);
  11:         HttpResponse response = new HttpResponse(new StringWriter());
  12:         HttpContext context = new HttpContext(request, response);
  13:         HttpContextBase contextWrapper = new HttpContextWrapper(context);
  14:         return routeData = RouteTable.Routes.GetRouteData(contextWrapper);
  15:     }
  16: }

具體的路由對映依然定義在新增的Global.asax檔案中。如下面的程式碼片斷所示,我們通過呼叫RouteTable的Routes屬性的MapRoute方法註冊了一個採用“{areacode}/{days}”作為URL模板的路由物件,並指定了預設變數、約束和名稱空間列表。

   1: public class Global : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start(object sender, EventArgs e)
   4:     {
   5:         object defaults = new { areacode = "010", days = 2, defaultCity="BeiJing", defaultDays=2};
   6:         object constraints = new { areacode = @"0\d{2,3}", days = @"[1-3]{1}"};
   7:         string[] namespaces = new string[] { "Artech.Web.Mvc", "Artech.Web.Mvc.Html" };
   8:         RouteTable.Routes.MapRoute("default", "{areacode}/{days}", defaults, constraints, namespaces);
   9:     }               
  10: }

如果我們現在在瀏覽器中訪問Default.aspx頁面,會得到下圖所示的結果,從中我們可以得到一些有用的資訊:

  • 與呼叫RouteCollection的MapPateRoute方法進行路由對映不同的是,這個得到的RouteData物件的RouteHandler屬性是一個System.Web.Mvc.MvcRouteHandler物件。
  • 在MapRoute方法中通過defaults引數指定的兩個與URL匹配無關的變數(defaultCity=BeiJing;defaultDays=2)體現在RouteData的Values屬性中。這意味著如果我們沒有在URL模板中為Controller和Action的名稱定義相應的變數({controller}和{action}),也可以將它們定義成預設變數。
  • DataTokens屬性中包含一個Key值為Namespaces值為字元陣列的元素,我們不難猜出它對應著我們指定的名稱空間列表。

clip_image002

三、基於Area的路由對映

對於一個較大規模的Web應用,我們可以從功能上通過Area將其劃分為較小的單元。每個Area相當於一個獨立的子系統,具有一套包含Models、Views和Controller在內的目錄結構和配置檔案。一般來說,每個Area具有各自的路由規則(URL模版上一般會體現Area的名稱),而基於Area的路由對映通過AreaRegistration進行註冊。

AreaRegistration與AreaRegistrationContext

基於Area的路由對映通過AreaRegistration進行註冊。如下面的程式碼片斷所示,AreaRegistration是一個抽象類,抽象只讀屬性AreaName返回當前Area的名稱,而抽象方法RegisterArea用於實現基於當前Area的路由註冊。

   1: public abstract class AreaRegistration
   2: {    
   3:     public static void RegisterAllAreas();
   4:     public static void RegisterAllAreas(object state);
   5:  
   6:     public abstract void RegisterArea(AreaRegistrationContext context);
   7:     public abstract string AreaName { get; }
   8: }

AreaRegistration定義了兩個抽象的靜態RegisterAllAreas方法過載,引數state用於傳遞給具體AreaRegistration的資料。當RegisterAllArea方法執行的時候,它先遍歷通過BuildManager的靜態方法GetReferencedAssemblies方法得到的編譯Web應用所使用的程式集,通過反射得到所有實現了介面IController的型別,並通過反射建立相應的AreaRegistration物件。對於每個AreaRegistration物件,一個AreaRegistrationContext物件被創建出來並作為引數呼叫它們的RegisterArea方法。

如下面的程式碼片斷所示,AreaRegistrationContext的只讀屬性AreaName表示Area的名稱,屬性Routes是一個代表路由表的RouteCollection物件,而State是一個使用者自定義物件,它們均通過建構函式進行初始化。具體來說,對於最初通過呼叫AreaRegistration的靜態方法RegisterAllAreas建立的AreaRegistrationContext物件,AreaName來源於當前AreaRegistration物件的同名屬性,Routes則對應著RouteTable的靜態屬性Routes表示的全域性路由表,而在呼叫RegisterAllAreas方法指定的引數(state)作為AreaRegistrationContext物件的State引數。

   1: public class AreaRegistrationContext
   2: {    
   3:     public AreaRegistrationContext(string areaName, RouteCollection routes);
   4:     public AreaRegistrationContext(string areaName, RouteCollection routes, object state);
   5:  
   6:     public Route MapRoute(string name, string url);
   7:     public Route MapRoute(string name, string url, object defaults);
   8:     public Route MapRoute(string name, string url, string[] namespaces);
   9:     public Route MapRoute(
            
           

相關推薦

ASP.NET MVC路由擴充套件路由對映

上週我寫了三篇文章(一、二、三)詳細地介紹了ASP.NET的路由系統。ASP.NET的路由系統旨在通過註冊URL模板與物理檔案之間的對映進而實現請求地址與檔案路徑之間的分離,但是對於ASP.NET MVC應用來說,請求的目標不再是一個具體的物理檔案,而是定義在某個Controller型別中的Action方法。

跟我學ASP.NET MVC之四使用Razor

ima pre 技術分享 C# 圖模型 med 執行 sys fonts 摘要: 視圖引擎處理ASP.NET內容,並查找指令,典型情況是向瀏覽器輸出插入動態內容。MVC框架視圖引擎的名字是Razor。 在本文中,我將帶領讀者快速認識Razor,以後你們看到他們的時候能夠

跟我學ASP.NET MVC之七SportsStrore購物車

repos ras img sports collect dev PC RM VC 摘要: SportsStore應用程序進展很順利,但是我不能銷售產品直到設計了一個購物車。在這篇文章裏,我就將創建一個購物車。 在目錄下的每個產品旁邊添加一個添加到購物車按鈕。點擊這個按

跟我學ASP.NET MVC之八SportsStrore移動設備

ima 支持 web瀏覽器 css 客戶端瀏覽器 nts oat 重新 menu 摘要: 現在的web程序開發避免不了智能手機和平板電腦上的使用,如果你希望發布你的應用程序給更廣大客戶使用的話,你將要擁抱可移動web瀏覽器的世界。向移動設備用戶發布一個好的使用體驗是很困難

Asp.Net MVC EF之一使用Database類在EF框架中執行Sql語句

包括 ans cti foo lists sele 下場 tex 對數 h4 { padding: 8px 5px; background-color: #32c5d2 } .start-box,.body { padding: 10px } .tit { font-siz

Asp.net Mvc Enum 擴充套件

消失月餘,擔心文筆生疏,今作簡單一篇小文試手。 一直以來都覺得enum、struct以及class是程式設計的基礎結構。 我們通常意圖用列舉來表示一些名稱的值屬性。有的時候用Enum來填充DropDownList也算是不錯的選擇。 假設我們有一個enum: public enum Role{

白話ASP.NET MVC之三Controller是如何解析出來的

    我們在上一篇文章中介紹Controller啟用系統中所涉及到的一些型別,比如有關Controller型別的相關定義型別就包括了IController型別,IAsyncController型別,ControllerBase抽象型別和我們最終要使用的抽象型別Contr

ASP.NET MVC路由擴充套件連結和URL的生成

ASP.NET 路由系統通過註冊的路由表旨在實現兩個“方向”的路有功能,即針對入棧請求的路由和出棧URL的生成。前者通過呼叫代表全域性路由表的RouteCollection物件的GetRouteData方法實現,後者則依賴於RouteCollection的GetVirtualPathData方法,而最終還是落

ASP.NET路由系統路由對映

總的來說,我們可以通過RouteTable的靜態屬性Routes得到一個基於應用的全域性路由表,通過上面的介紹我們知道這是一個型別的RouteCollection的集合物件,我們可以通過呼叫它的MapPageRoute進行路由對映,即註冊URL模板與某個物理檔案的匹配關係。路由註冊的核心就是在全域性路由表中新

ASP.NET MVC5 新特性Attribute路由使用詳解

ref 否則 back default static 引入 擁有 bsp pathinfo 1、什麽是Attribute路由?怎麽樣啟用Attribute路由?   微軟在 ASP.NET MVC5 中引入了一種新型路由:Attribute路由,顧名思義,Attribute

asp.net MVC 5 路由 Routing

onf 模型 控制 ace 讓我 view 字符 blog cal ASP.NET MVC ,一個適用於WEB應用程序的經典模型 model-view-controller 模式。相對於web forms一個單一的整塊,asp.net mvc是由連接在一起的各種代碼層所組成

ASP.NET沒有魔法——ASP.NET MVC路由

文件相對路徑 register 以及 out insert 技術分享 順序 reg 沒有   之前的文章中介紹了My Blog文章維護功能的開發,開發過程中使用Area的方法建立了用於維護文章的Controller、View和Model。但是無論代碼怎麽變對於瀏覽器來說都是

Asp.Net MVC 路由

oba ica 除了 xxx eas url hello register 可選參數 Asp.Net MVC 路由 使用URL請求應用程序時,該請求最終是通過Handler來完成,Asp.Net MVC 是通過一個自定義的HttpHandler--MVCHandler來實

ASP.NET MVC中的路由IRouteConstraint方法應用實例

http col spa Go clas .aspx direct lec rep 在如下代碼的寫法中: public class RouteConfig { public static void RegisterRoutes(RouteColle

asp.net mvc獲取路由參數

如何獲取 其他 htm ted ext 發現 ID arp value 學習了mvc有一段時間了,本以為直接可以通過request對象直接獲取路由參數呢,後來實驗了一下發現想錯了,mvc有專門獲取路由參數的方式,在不同的地方,獲取路由參數的方式也不一樣,這裏分別說一下,在c

一、ASP.NET MVC 路由(一)--- ASP.NET WebForm路由模擬

      ASP.NET WebForm 應用,使用者請求的是物理檔案,其中包括靜態頁面和動態頁面,在Url中的顯示都是伺服器中一個物理檔案的相對路徑。但是ASP.NET MVC就不同了,使用者請求的是Controller中一個Action方法,這種請求是通過路由將Url對映到相對的Controller

asp.net mvc設定area頁面為預設路由

1.在routeconfig裡新增如下程式碼: routes.MapRoute( name: "Default", url: "{con

asp.net mvc路由重寫及偽靜態的粗淺理解

關於路由 ASP.NET MVC中一個重要的內容就是路由,關於路由簡單的理解就是瀏覽器提出請求,然後通過路由表將請求匹配到相應的MVC控制器! 第一種方式可以在web.config 裡面修改

ASP.NET MVC-輕鬆理解Routing(路由

先來看下面兩個個url,對比一下: http://xxx.yyy.com/Admin/UserManager.aspx http://xxx.yyy.com/Admin/DeleteUser/1001     對於第1個Url,假設它與伺服器上的檔案有直接

ASP.NET MVC URL重寫與優化(初級篇)-使用Global路由表定製URL

在現今搜尋引擎制霸天下的時代,我們不得不做一些東西來討好爬蟲,進而提示網站的排名來博得一個看得過去的流量。   URL重寫與優化就是搜尋引擎優化的手段之一。   假如某手機網站(基於ASP.NET MVC)分類頁面URL是這樣的,   http://www.xxx.