剖析Asp.Net路由系统实现原理
对于asp.net web forms应用来说,请求的url都是对应一个具体的物理文件(http://xxx.com/default.aspx)。这样的url与具体物理文件紧密绑定在一起,带来了诸多方便的局限:可读性、seo优化等。为了解决这些局限性,微软引入了url路由系统。下面通过一个demo来剖析一下asp.net的路由系统。
创建一个空的webform应用程序,在global.asax.cs文件中加入如下代码:
public class global : system.web.httpapplication { protected void application_start(object sender, eventargs e) { //处理匹配的文件 routetable.routes.routeexistingfiles = true; //url默认值 routevaluedictionary defaults = new routevaluedictionary() { { "name", "wuwenmao" }, { "id", "001" } }; //路由约束 routevaluedictionary constraints = new routevaluedictionary() { { "name", @"\w{2,10}" }, { "id", @"\d{3}" } }; //与路由相关的值,但不参与路由是否匹配url模式 routevaluedictionary datatokens = new routevaluedictionary() { { "defaultname", "wuwenmao" }, { "defaultid", "001" } }; routetable.routes.mappageroute("default", "employees/{name}/{id}", "~/default.aspx", false, defaults, constraints, datatokens); } }
新建名为default的webform页面,页面代码如下:
<%@ page language="c#" autoeventwireup="true" codebehind="default.aspx.cs" inherits="webapplication2.default" %> <!doctype html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title></title> </head> <body> <form id="form1" runat="server"> <h1>这是default.aspx页面</h1> <div> routedata中values: <ul> <% foreach (var value in routedata.values) { %> <li> <%=value.key %>=<%=value.value %> </li> <%} %> </ul> routedata中datatokens: <ul> <% foreach (var value in routedata.datatokens) { %> <li> <%=value.key %>=<%=value.value %> </li> <%} %> </ul> </div> </form> </body> </html>
输入路径为一下三种,得到的结果都是一样的:
http://localhost:2947/employees/wuwenmao/001
http://localhost:2947/employees/wuwenmao
http://localhost:2947/employees/
原因是因为注册路由的时候,为路由模板中的变量设置了默认值,所以当用以上三种url时是等效的。
回头看global文件中,在注册路由时还设置了一个变量:
这是使用正则规则限定了路由模板中变量的值,请求url中对应的变量值只有与正则匹配才能正确请求,否则返回404错误。如id值长度大于3时:
上面通过一个简单的例子体验了一下asp.net路由系统,下面我们通过翻看源码来剖析一下asp.net路由系统的实现原理。
首先,我们global文件中使用以下语句注册一个路由时,实际上是向全局路由表添加一个路由。
通过reflector工具,我们可以看到:
现在有个问题,在注册好路由之后,asp.net是如何使用路由系统的呢?实际上,asp.net路由系统是通过注册一个httpmodule对象,由这个httpmodule对象实现针对请求进行拦截,然后动态映射到用于处理当前请求的httphandler对象中,最后通过httphandler对象对请求进行处理并响应。这个httpmodule实际上就是urlroutingmodule,我们在启动asp.net程序时,通过global文件中的modules属性可以验证,从下面截图可以看到,modules属性中包含了已经注册的httpmodule,其中就包含urlroutingmodule:
在这个urlroutingmodule里面,又进行了哪些跟路由相关的操作呢,我们还是继续翻看源码:
通过上面的源码查看,我们可以看出,当有请求来到时,asp.net通过注册的urlroutingmodule模块拦截了请求,然后从全局路由表中查找匹配的routedata,如果找得到,根据httpapplication获取到对应的httphandler,然后将其映射到当前请求上下文中,供后续的管道事件用以处理当前请求。
下面我们继续翻看源码,剖析一下urlroutingmodule是怎么从全局路由表中获取routedata的:
从上面可以看到,urlroutingmodule中调用全局路由表的getroutedata,实际上是依次调用注册的每个route的getroutedata,返回第一个匹配的routedata,如果注册的路由都不匹配,返回null。
下面我们再来看看route里面的getroutedata做了些什么:
match方法:
通过依次调用route的getroutedata方法,在getroutedata方法中做了如下操作:
1、调用了parsedroute类型的match方法进行请求url和注册在当前route对象中的路由模板的匹配工作,如果没有匹配,直接返回null;
2、如果请求url和当前route对象的路由模板匹配了,常见routedata对象;
3、根据注册路由信息时定义的约束条件来检验当前请求url是否通过,不通过返回null;
4、为routedata对象的values和datatokens赋值操作;
5、返回routedata对象;
到此,asp.net的路由系统基本上剖析完毕,还有很多细节限于篇幅没办法一一剖析。
总结:
通过以上的剖析,我们整理一下思路,对asp.net路由系统所做的工作做个总结:首先,我们在global中注册了route对象,然后通过在asp.net注册的httpmodule模块urlroutingmodule进行拦截请求url,之后从全局路由表routetables.routes中依次调用route对象的getroutedata进行请求url和注册路由信息的匹配,返回第一个匹配的routedata,查找完整个routetables.routes后没有匹配到,返回null,最终会返回404给前端页面。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: CAD2014怎么调整标注的尺寸与样式?