<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      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(string name, string url, object defaults, object constraints);
        10:     public Route MapRoute(string name, string url, object defaults, string[] namespaces);
        11:     public Route MapRoute(string name, string url, object defaults, object constraints, string[] namespaces);
        12:  
        13:     public string AreaName { get; }
        14:     public RouteCollection Routes { get; }
        15:     public object State { get; }
        16:     public ICollection<string> Namespaces { get; }
        17: }

      AreaRegistrationContext的只讀屬性Namespaces表示一組優先匹配的命名空間(當多個同名的Controller類型定義在不同的命名空間中)。當針對某個具體AreaRegistration的AreaRegistrationContext被創建的時候,如果AreaRegistration類型具有命名空間,那么會在這個命名空間基礎上添加“.*”后綴并添加到Namespaces集合中。換言之,對于多個定義在不同命名空間中的同名Controller類型,會優先選擇包含在當前AreaRegistration命名空間下的Controller

      AreaRegistrationContext定義了一系列的MapRoute用于進行路由映射注冊,方法的使用以及參數的含義與定義在RouteCollectionExtensions類型中的同名擴展方法一致。在這里需要特別指出的是,如果MapRoute方法沒有指定命名空間,則通過屬性Namespaces表示的命名空間列表會被使用;反之,該屬性中包含的命名空間被直接忽略

      當我們通過Visual Studio的ASP.NET MVC項目模版創建一個Web應用的時候,在的Global.asax文件中會生成如下的代碼通過調用AreaRegistration的靜態方法RegisterAllAreas實現對所有Area的注冊,也就是說針對所有Area的注冊發生在應用啟動的時候。

         1: public class MvcApplication : System.Web.HttpApplication
         2: {
         3:     protected void Application_Start()
         4:     {
         5:         AreaRegistration.RegisterAllAreas();
         6:     }
         7: }

      AreaRegistration的緩存

      Area的注冊(主要是基于Area的路由映射注冊)通過具體的AreaRegistration來實現。在應用啟動的時候,為了實現對所有Area的注冊,需要遍歷通過調用BuildManager的靜態方法GetReferencedAssemblies方法得到的程序集列表,并通過從中找到所有AreaRegistration類型。如果一個應用涉及到太多的程序集,這個過程可能會耗費很多時間,為了提供性能,基于AreaRegistration類型列表的緩存被采用。

      注:BuildManager的靜態方法GetReferencedAssemblies返回所有頁編譯都必須引用的程序集引用的列表,這包括包含 Web.config 文件的<system.web>/<compilation>/<assemblies>配置節中指定的用于編譯Web應用所使用的程序集和從 App_Code 目錄中的自定義代碼生成的程序集以及其他頂級文件夾中的程序集。

      ASP.NET MVC對AreaRegistration類型列表的緩存是基于文件的。具體來說,當通過程序集加載和反射得到了所有的AreaRegistration類型列表后,會將其進行序列化并被保存為一個XML物理文件,這個名為MVC-AreaRegistrationTypeCache.xml的XML文件被存放在ASP.NET的臨時目錄下,具體的路徑如下。其中第一個針對寄宿于IIS中的Web應用,后者針對直接通過Visual Studio Developer Server作為宿主的應用。

      • %Windir%\Microsoft.NET\Framework\v{version}\Temporary ASP.NET Files\{appname}\...\...\UserCache\
      • %Windir%\Microsoft.NET\Framework\v{version}\Temporary ASP.NET Files\root\...\...\UserCache\

      下面的XML片斷體現了這個作為所有AreaRegistration類型緩存的XML文件的結構,從中我們可以看到所有的AreaRegistration類型名稱,連同它所在的托管模塊和程序集名稱都被保存了下來。當調用AreaRegistration的靜態方法RegisterAllAreas被調用之后,系統會試圖加載該文件,如果該文件存在并且具有期望的結構,那么將不在通過程序集加載和反射來解析AreaRegistration的類型,而是直接對文件內容進行反序列化從而得到所有AreaRegistration類型的列表。

         1: <?xml version="1.0" encoding="utf-8"?>
         2: <!--This file is automatically generated. Please do not modify the contents of this file.-->
         3: <typeCache lastModified="3/22/2012 2:58:47 PM" mvcVersionId="80365b23-7a1d-42b2-9e7d-cc6f5694c6d1">
         4:   <assembly name="Artech.Admin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
         5:     <module versionId="07be22a1-781d-4ade-bd22-34b0850445ef">
         6:       <type>Artech.Admin.AdminAreaRegistration</type>
         7:     </module>
         8:   </assembly>
         9:   <assembly name="Artech.Portal, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
        10:     <module versionId="7b0490d4-427e-43cb-8cb5-ac1292bd4976">
        11:       <type>Artech.Portal.PortalAreaRegistration</type>
        12:     </module>
        13:   </assembly>
        14: </typeCache>

      實例演示:查看基于Area路由信息

      通過AreaRegistration實現的針對Area的路由注冊具有一些特殊的細節差異,我們通過實例演示的方式來說明。我們直接使用前面創建的演示實例,并在項目中創建一個自定義的WeatherAreaRegistration。如下面的代碼片斷所示,WeatherAreaRegistration繼承自抽象基類AreaRegistration,表示Area名稱的AreaName屬性返回“Weahter”。在實現路由注冊的RegisterArea方法中我們調用AreaRegistrationContext對象的MapRoute方法注冊了一個URL模版為“weather/{areacode}/{days}"的路由對象。默認變量值、約束也被相應地提供。[源代碼從這里下載]

         1: public class WeatherAreaRegistration : AreaRegistration
         2: {
         3:     public override string AreaName
         4:     {
         5:         get { return "Weather"; }
         6:     }
         7:     public override void RegisterArea(AreaRegistrationContext context)
         8:     {
         9:         object defaults = new { areacode = "010", days = 2, defaultCity = "BeiJing", defaultDays = 2 };
        10:         object constraints = new { areacode = @"0\d{2,3}", days = @"[1-3]{1}" };
        11:         context.MapRoute("weatherDefault", "weather/{areacode}/{days}", defaults, constraints);
        12:     }
        13: }

      我們在Global.asax的Application_Start方法中按照如下的方式調用AreaRegistration的靜態方法RegisterAllAreas實現對所有Area的注冊。按照我們在上面介紹的Area注冊原理,對于第一次RegisterAllAreas方法的調用,會自動加載所有引用的程序集來獲取所有的AreaRegistration(當然就包括我們上面定義的WeatherAreaRegistration),最后通過反射創建相應的對象并調用RegisterArea方法。

         1: public class Global : System.Web.HttpApplication
         2: {
         3:     protected void Application_Start(object sender, EventArgs e)
         4:     {
         5:         AreaRegistration.RegisterAllAreas();
         6:     }
         7: }

      對于定義在Default.aspx頁面后臺代碼中用于進行路由匹配和獲取路由信息的GetRouteData方法中,我們對創建的HttpRequest對象略加修改,使請求地址符合通過WeatherAreaRegistration注冊的路由規則(/weather/0512/3)。

         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/weather/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: }

      在瀏覽器中訪問Default.aspx頁面,我們會得到如圖2-10所示的結果。通過AreaRegistration注冊的路由對象得到的RouteData的不同之處主要反映在其DataTokens屬性上。如下圖所示,除了表示命名空間列表的元素,DataTokens屬性表示的RouteValueDictionary還具有兩個額外的元素,其中一個Key為“area”的元素代表Area的名稱,另一個Key為“UseNamespaceFallback”的元素具有一個布爾類型的值表示是否需要使用后備的命名空間來解析Controller的類型。

      clip_image002[4]

      如果調用AreaRegistrationContext的MapRoute方法是顯式指定了命名空間,或者說對應的AreaRegistration定義在某個命名空間下,這個名稱為“UseNamespaceFallback”的DataToken元素的值為False;反之為True。進一步來說,如果在調用MapRoute方法時指定了命名空間列表,那么AreaRegistration類型所示在命名空間會被忽略。也就是說,后者是前者的一個后備,前者具有更高的優先級。

      AreaRegistration類型所示在命名空間也不說直接作為最終RouteData的DataTokens中的命名空間,而是在此基礎上加上“.*”后綴。如果對本實例得到得到包含RouteData的DataTokens集合中的命名空間,你會發現其值為“WebApp.*”(WebApp是定義WeatherAreaRegistration的命名空間)。

      ASP.NET MVC路由展:路由映射
      ASP.NET MVC路由擴展:鏈接和URL的生成

      posted @ 2012-03-26 08:14  Artech  閱讀(39527)  評論(43)    收藏  舉報
      主站蜘蛛池模板: 国产精品国产片在线观看| 97se亚洲综合在线天天| 免费的很黄很污的视频| 亚洲人成自拍网站在线观看| 久久一区二区中文字幕| 婷婷五月综合丁香在线| 国产精品夫妇激情啪发布| 九九在线精品国产| 黄页网站在线观看免费视频| 国产偷国产偷亚洲高清午夜| 丰满妇女强制高潮18xxxx| 一本大道久久香蕉成人网| 亚洲午夜精品久久久久久浪潮| 国产av精品一区二区三区| 国产午夜福利在线视频| 华人在线亚洲欧美精品| 成在线人免费视频| 久久久无码精品国产一区| 国产95在线 | 欧美| 夜夜添狠狠添高潮出水| 潘金莲高清dvd碟片| 国产欲女高潮正在播放| 97人人添人人澡人人澡人人澡| 亚洲av色在线观看国产| 国产一区二区av天堂热| 99视频在线精品国自产拍| 亚洲精品日韩在线丰满| 中文字幕制服国产精品| 国产精品美女免费无遮挡| 国产不卡精品视频男人的天堂| 亚洲精品中文综合第一页| 成年女人片免费视频播放A| 亚洲中文精品一区二区| 亚洲欧美日韩久久一区二区| 国产精品熟女孕妇一区二区| 久久国产乱子精品免费女| 亚洲熟妇一区二区三个区| 男受被做哭激烈娇喘gv视频| 亚洲精品无码你懂的| gogogo在线播放中国| 香蕉EEWW99国产精选免费|