• 剖析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给前端页面。

          至此,Asp.Net路由系统的剖析完毕,个人能力有限,如有不对或欠缺的地方,博友们尽可以提出修正。

  • 相关阅读:
    jquery插件实现瀑布流
    mysql explain亲测
    html5 audio标签微信部分苹果手机不能自动播放音乐终极解决方案
    mysql主从复制笔记
    mysql主从复制报错解决方案
    php form表单ajax上传图片方法
    Android webView 正确的用法
    【博弈】【HDU】取石子游戏
    Gleb And Pizza CodeForces
    Kirill And The Game CodeForces
  • 原文地址:https://www.cnblogs.com/wuwenmao/p/6398320.html
Copyright © 2020-2023  润新知