总的来说,我们可以通过RouteTable的静态属性Routes得到一个基于应用的全局路由表,通过上面的介绍我们知道这是一个类型的RouteCollection的集合对象,我们可以通过调用它的MapPageRoute进行路由映射,即注册URL模板与某个物理文件的匹配关系。路由注册的核心就是在全局路由表中添加一个Route对象,该对象的绝大部分属性都可以通过MapPageRoute方法的相关参数来指定。接下来我们通过实现演示的方式来说明路由注册的一些细节问题。

目录 
一、变量默认值 
二、约束 
三、对现成文件的路由 
四、注册路由忽略地址 
五、直接添加路由对象

我们已前面介绍的关于获取天气预报信息的路由地址,我们在创建的ASP.NET Web应用中创建一个Weather.aspx页面,不过我们并不打算在该页面中呈现任何天气信息,而是将基于该页面的路由信息打印出来。该页面主体部分的HTML如下所示,我们不仅将基于当前页面的RouteData对象的Route和RouteHandler属性类型输出来,还将存储于Values和DataTokens字典的变量显示出来。

   1: <body>
   2:     <form id="form1" runat="server">
   3:     <div>
   4:         <table>
   5:             <tr>
   6:                 <td>Route:</td>
   7:                 <td><%=RouteData.Route != null? RouteData.Route.GetType().FullName:"" %></td>
   8:             </tr>
   9:             <tr>
  10:                 <td>RouteHandler:</td>
  11:                 <td><%=RouteData.RouteHandler != null? RouteData.RouteHandler.GetType().FullName:"" %></td>
  12:             </tr>
  13:             <tr>
  14:                 <td>Values:</td>
  15:                 <td>
  16:                     <ul>
  17:                         <%foreach (var variable in RouteData.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 RouteData.DataTokens)
  29:                           {%>
  30:                         <li><%=variable.Key%>=<%=variable.Value%></li>
  31:                         <% }%>
  32:                     </ul>
  33:                 </td>
  34:             </tr>
  35:         </table>
  36:     </div>
  37:     </form>
  38: </body>

在添加的Global.asax文件中,我们将路由注册操作定义在Application_Start方法中。如下面的代码片断所示,映射到weather.aspx页面的URL模板为{areacode}/{days}。在调用MapPageRoute方法的时候,我们还为定义在URL模板的两个变量定义了默认值以及正则表达式。除此之外,我们还在注册的路由对象上附加了两个变量,表示对变量默认值的说明(defaultCity:BeiJing;defaultDays:2)。

   1: public class Global : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start(object sender, EventArgs e)
   4:     {
   5:         var defaults = new RouteValueDictionary { { "areacode", "010" }, { "days", 2 }};
   6:         var constaints = new RouteValueDictionary { { "areacode", @"0\d{2,3}" }, { "days", @"[1-3]{1}" } };
   7:         var dataTokens = new RouteValueDictionary { { "defaultCity", "BeiJing" }, { "defaultDays", 2 } };
   8:         
   9:         RouteTable.Routes.MapPageRoute("default", "{areacode}/{days}", "~/weather.aspx", false, defaults, constaints, dataTokens);
  10:     }
  11: }

一、变量默认值

由于我们为定义在URL模板中表示区号和天数的变量定义了默认值(areacode:010;days:2),如果我们希望返回北京地区未来两天的天气,可以直接访问应用根地址,也可以只指定具体区号,或者同时指定区号和天数。如下图所示,当我们在浏览器地址栏中输入上述三种不同的URL会得到相同的输出结果。

从下图所示的路由信息我们可以看到,默认情况下RouteData的Route属性类型正是Route,而RouteHandler属性则一个是PageRouteHandler对象,我们会在本章后续部分对PageRouteHandler进行详细介绍。通过地址解析出来的变量被存储数Values属性中,而在进行路由注册过程为Route对象DataTokens属性定义的变量被转移到了RouteData的同名属性中。[实例源代码下载]

二、约束

我们以电话区号代表对应的城市,为了确保用户在的请求地址中提供有效的区号,我们通过正则表达式(“0\d{2,3}”)对其进行了约束。此外,我们只能提供未来3天以内的天气情况,我们同样通过正则表达式(“[1-3]{1}”)是对请求地址中表示天数的变量进行了约束。如果请求地址中的内容不能符合相关变量段的约束条件,则意味着对应的路由对象与之不匹配。

对于本例来说,由于我们只注册了唯一的路由对象,如果请求地址不能满足我们定义的约束条件,则意味着找不到一个具体目标文件,会返回404错误。如下图所示,由于在请求地址中指定了不合法的区号(01)和天数(4),我们直接在浏览器界面上得到一个HTTP 404错误。

对于约束,除了可以通过字符串的形式为某个变量定义相应的正则表达式之外,我们还可以指定一个实现了IRouteConstraint接口的类型的对象对整个请求进行约束。如下面的代码片断所示,IRouteConstraint具有唯一的方法Match用于定义约束的逻辑,该方法的5个参数分别表示:HTTP上下文、当前路由对象、约束的名称(存储约束对象的RouteValueDictionary的Key)、解析被匹配URL得到的变量集合以及表示路由的方向。

   1: public interface IRouteConstraint
   2: {
   3:     bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
   4: }
   5: public enum RouteDirection
   6: {
   7:     IncomingRequest,
   8:     UrlGeneration
   9: }

所谓路由的方向表示是针对请求匹配(入栈)还是针对URL的生成(出栈),分别通过如上所示的枚举类型RouteDirection的两个枚举值表示。具体来说,当调用路由对象的GetRouteData和GetVirtualPathData方法时,枚举值IncomingRequest和UrlGeneration分别被采用。

ASP.NET路由系统的应用编程接口中定义了如下一个实现了IRouteConstraint接口的HttpMethodConstraint类型。顾名思义,HttpMethodConstraint提供针对HTTP方法(GET、POST、PUT、DELTE等)的约束。我们可以通过HttpMethodConstraint为路由对象设置一个允许的HTTP方法列表,只有方法名称在这个指定的列表中的HTTP请求才允许被路由。这个被允许被路由的HTTP方法列表对于HttpMethodConstraint的只读属性AllowedMethods,并在构造函数中初始化。

   1: public class HttpMethodConstraint : IRouteConstraint
   2: {
   3:     public HttpMethodConstraint(params string[] allowedMethods);    
   4:     bool IRouteConstraint.Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
   5:     public ICollection<string> AllowedMethods {  get;  }
   6: }

同样是针对我们演示的例子,我们在进行路由注册的时候通过如下的代表应用了一个类型为HttpMethodConstraint的约束,并将允许的HTTP方法设置为POST,意味着被注册的Route对象仅限于路由POST请求。

   1: public class Global : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start(object sender, EventArgs e)
   4:     {
   5:         var defaults = new RouteValueDictionary { { "areacode", "010" }, { "days", 2 } };
   6:         var constaints = new RouteValueDictionary { { "areacode", @"0\d{2,3}" }, { "days", @"[1-3]{1}" }, { "httpMethod", new HttpMethodConstraint("POST") } };
   7:         var dataTokens = new RouteValueDictionary { { "defaultCity", "BeiJing" }, { "defaultDays", 2 } };
   8:         
   9:         RouteTable.Routes.MapPageRoute("default", "{areacode}/{days}", "~/weather.aspx", false, defaults, constaints, dataTokens);
  10:     }
  11: }

现在我们采用与注册的URL模板相匹配的地址(/010/2)来访问Weather.aspx页面,依然会得到如下图所示的404错误。[实例源代码下载]

三、对现有文件的路由

在成功注册路由的情况下,如果我们按照传统的方式访问一个物理文件(比如.asxp、.css或者.js等),在请求地址满足某个路由的URL模板模式的情况下,ASP.NET是否还是正常实施路由呢?我们不妨通过我们的实例还测试一下。为了让针对某个物理文件的访问地址也满足注册路由对象的URL模板模式,我们需要按照如下的方式将上面定义的关于正则表达式约束删除。

   1: public class Global : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start(object sender, EventArgs e)
   4:     {
   5:         var defaults = new RouteValueDictionary { { "areacode", "010" }, { "days", 2 }};
   6:         //var constaints = new RouteValueDictionary { { "areacode", @"0\d{2,3}" }, { "days", @"[1-3]{1}" } };
   7:         var dataTokens = new RouteValueDictionary { { "defaultCity", "BeiJing" }, { "defaultDays", 2 } };
   8:         
   9:         RouteTable.Routes.MapPageRoute("default", "{areacode}/{days}", "~/weather.aspx", false, defaults, null, dataTokens);
  10:     }
  11: }

当我们通过传统的方式来访问存放于根目录下的weather.aspx页面时会得到如下图所示的结果。从界面上的输出结果我们不难看出,虽然请求地址完全满足我们注册路由对象的URL模板模式,但是ASP.NET并没有对请求地址实施路由。原因很简单,如果中间发生了路由,基于页面的RouteData的各项属性都不可能为空。[实例源代码下载]

那么是否意味着如果请求地址对应着一个现存的物理文件,ASP.NET就会自动忽略路由呢?实则不然,或者说不对现有文件实施路由仅仅默认采用的行为。是否对现有文件实施路由取决于代表全局路由表的RouteCollection对象的RouteExistingFiles属性,该属性默认情况下为False,我们可以将此属性设置为True使ASP.NET路由系统忽略现有物理文件的存在,总是按照注册的路由表进行路由。为了演示这种情况下,我们对Global.asax文件作了如下的改动,在进行路由注册之前将RouteTable的Routes属性代表的RouteCollection对象的RouteExistingFiles属性设置为True。

   1: public class Global : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start(object sender, EventArgs e)
   4:     {
   5:         RouteTable.Routes.RouteExistingFiles = true;
   6:         var defaults = new RouteValueDictionary { { "areacode", "010" }, { "days", 2 } };
   7:         var dataTokens = new RouteValueDictionary { { "defaultCity", "BeiJing" }, { "defaultDays", 2 } };
   8:         
   9:          RouteTable.Routes.MapPageRoute("default", "{areacode}/{days}", "~/weather.aspx", false, defaults, null, dataTokens);
  10:     }
  11: }

依旧是针对weather.aspx页面的访问,我们却得到不一样的结果。从下图中我们可以看到,针对页面的相对地址weather.aspx不再指向具体的Web页面,在这里就是一个表示获取的天气信息对应的目标城市(areacode=weather.aspx)。[实例源代码下载]

四、注册路由忽略地址

如果将代表全局路由表的RouteTable的静态属性Routes的RouteExistingFiles属性设置为True,意味着ASP.NET针对所有抵达的请求都一视同仁,都按照注册的路由表进行注册,但这会代码一些问题。不知道读者有没有发现上图所示的页面具有不一样的格式(标签部分没有加粗,也没有居右上对齐),这是因为这是采用了jQuery的方式来控制的,为此我们必须按照如下的方式来饮用jQuery相关的脚本文件。

   1: <script src="/jquery-1.4.1.min.js" type="text/javascript"></script>

但是由于我们将全局路由表的RouteExistingFiles属性设置为True,意味着针对上面这个.js脚本文件的访问也会被路由。根据我们注册的路由规则,针对这个文件的访问会自动被导向weather.aspx这个页面。如下图所示,我们直接在浏览器的地址栏中属性.js文件的地址,呈现出来还是我们熟悉的界面(areacode=jquery-1.4.1.min.js)。[实例源代码下载]

这是一个不得不解决的问题,因为它是我们无法正常地在页面中引用向javascript和css文件。我们可以通过调用RouteCollection的Igore方法来注册一些需要让路由系统忽略的URL模板。从前面给出的关于RouteCollection的定义我们可以看到它具有两个Igore重载,除了指定需要忽略的URL模板之外,我们还可以对相关的变量定义约束正则表达式。为了让ASP.NET路由系统忽略掉针对.js文件请求,我们可以按照如下的方式在Global.asax中调用RouteTable的Routes属性的Ignore方法。[实例源代码下载]

   1: public class Global : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start(object sender, EventArgs e)
   4:     {
   5:         RouteTable.Routes.RouteExistingFiles = true;
   6:         RouteTable.Routes.Ignore("{filename}.js/{*pathInfo}");
   7:         //其他操作
   8:     }
   9: }

五、直接添加路由对象

当我们调用RouteCollection对象的MapPageRoute方法进行路由注册的本质就在路由字典中添加Route对象,所以我们完全调用Add方法添加一个手工创建的Route对象,如下所示的两种路由注册方式是完全等效的。如果我们需要添加一个继承自RouteBase的自定义路由对象,我们不得不采用手工添加的方式。

   1: public class Global : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start(object sender, EventArgs e)
   4:     {
   5:         var defaults = new RouteValueDictionary { { "areacode", "010" }, { "days", 2 }};
   6:         var constaints = new RouteValueDictionary { { "areacode", @"0\d{2,3}" }, { "days", @"[1-3]{1}" } };
   7:         var dataTokens = new RouteValueDictionary { { "defaultCity", "BeiJing" }, { "defaultDays", 2 } };
   8:  
   9:         //路由注册方式1
  10:         RouteTable.Routes.MapPageRoute("default", "{areacode}/{days}", "~/weather.aspx", false, defaults, constaints, dataTokens);
  11:  
  12:         //路由注册方式2
  13:         Route route = new Route("{areacode}/{days}", defaults, constaints, dataTokens, new PageRouteHandler("~/weather.aspx", false));
  14:         RouteTable.Routes.Add("default", route);
  15:     }
  16: }

ASP.NET的路由系统:URL与物理文件的分离 
ASP.NET的路由系统:路由映射 
ASP.NET的路由系统:根据路由规则生成URL

ASP.NET的路由系统:路由映射的更多相关文章

  1. ASP.NET MVC3中的路由系统 Routes

    MVC中,用户访问的地址并不映射到服务器中对应的文件,而是映射到对应Control里对应的ActionMethod,由ActionMethod来决定返回用户什么样的信息.而把用户访问的地址对应到对应的 ...

  2. ASP.NET MVC3中的路由系统(Routes) .

    MVC中,用户访问的地址并不映射到服务器中对应的文件,而是映射到对应Control里对应的ActionMethod,由ActionMethod来决定返回用户什么样的信息.而把用户访问的地址对应到对应的 ...

  3. ASP.NET MVC3中的路由系统

    MVC中,用户访问的地址并不映射到服务器中对应的文件,而是映射到对应Control里对应的ActionMethod,由ActionMethod来决定返回用户什么样的信息.而把用户访问的地址对应到对应的 ...

  4. MVC3中的路由系统(Routes)

    转载:http://blog.csdn.net/francislaw/article/details/7429317 MVC中,用户访问的地址并不映射到服务器中对应的文件,而是映射到对应Control ...

  5. Django之URL(路由系统)用法

    路由系统 路由系统概念 简而言之,路由系统就是路径和视图函数的一个对应关系.django的路由系统作用就是使views里面处理数据的函数与请求的url建立映射关系.使请求到来之后,根据urls.py里 ...

  6. [oldboy-django][2深入django]django目录说明 + 路由系统

    django project目录说明 project - app01 -- admin.py #django自带后台管理 -- apps.py #app01配置文件 -- models.py #编写类 ...

  7. Django 的路由系统

    Django 的路由系统   Django 的路由系统 路由层 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$',views.ho ...

  8. django框架基础-路由系统-长期维护

    ##################   路由系统介绍    ####################### 路由系统就是路径和函数的对应关系, 路由系统可以看成支撑你这个网站的目录,就像是一本书一样 ...

  9. Flask之路由系统

    路由系统 路由的两种写法 1.第一种方法: def index(): return render_template('index.html') app.add_url_rule('/index', ' ...

  10. ASP.NET路由系统实现原理:HttpHandler的动态映射

    我们知道一个请求最终通过一个具体的HttpHandler进行处理,而我们熟悉的用于表示一个Web页面的Page对象就是一个HttpHandler,被用于处理基于某个.aspx文件的请求.我们可以通过H ...

随机推荐

  1. Emmet 记录

    Refs 熟悉 css 有优势,emmet 的的缩写语法特别像 css 选择器. =>参考本博笔记 # id > 直接子元素 child . class + Sibling 同级相邻的一个 ...

  2. php时间转换

    UNIX时间戳和格式化日期是我们常打交道的两个时间表示形式,Unix时间戳存储.处理方便,但是不直观,格式化日期直观,但是处理起来不如Unix时间戳那么自如,所以有的时候需要互相转换,下面给出互相转换 ...

  3. QObject

    from PyQt5.QtCore import QObject 设置属性: QObject.__subclasses__() 返回所有子类 obj.setObjectName('ppp')    设 ...

  4. git修改文件夹名字

    git mv -f oldfolder newfolder git add -u newfolder (-u选项会更新已经追踪的文件和文件夹) git commit -m "changed ...

  5. spring boot 与 spring cloud 关系

    公司使用spring cloud,所以稍微了解一下 看了一下spring官网对 spring boot 以及 spring cloud 的解释 Spring Boot Spring Boot make ...

  6. Django REST framework 第二章 Request and Response

    此章节开始真正的撰写REST framework的核心代码,介绍一系列必要的建立设计 Request Objects REST framework介绍了一个Request对象用来扩展常规的HttpRe ...

  7. eclipse使用异常An error has occurred.see error log for more details eclipse

    eclipse使用异常An error has occurred.see error log for more details eclipse 解决Eclipse,MyEclipse出现An erro ...

  8. Create AI Guard Class

    创建FPSAIGuard类 不需要玩家输入,删除多余的函数 FPSAIGuard.h #include "CoreMinimal.h" #include "GameFra ...

  9. SpringSecurity如何在代码中获取认证用户信息

    ⒈ public Object getCurrentUser(){ return SecurityContextHolder.getContext().getAuthentication(); } ⒉ ...

  10. [转]python3之paramiko模块(基于ssh连接进行远程登录服务器执行命令和上传下载文件的功能)

    转自:https://www.cnblogs.com/zhangxinqi/p/8372774.html 阅读目录 1.paramiko模块介绍 2.paramiko的使用方法 回到顶部 1.para ...