WEB开发网
开发学院WEB开发ASP.NET ASP.NET MVC路由扩展:路由映射 阅读

ASP.NET MVC路由扩展:路由映射

 2012-03-26 11:39:19 来源:WEB开发网   
核心提示: 6: } 7: }对于定义在Default.aspx页面后台代码中用于进行路由匹配和获取路由信息的GetRouteData方法中,我们对创建的HttpRequest对象略加修改,ASP.NET MVC路由扩展:路由映射(8),使请求地址符合通过WeatherAreaRegistration注册的路由规
   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
 
 
 
 
三、基于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的命名空间)。
 

上一页  3 4 5 6 7 8 

Tags:ASP NET MVC

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接