彩票走势图

ASP.NET MVC路由匹配检测组件的代码分析

原创|其它|编辑:郝浩|2009-09-27 11:09:11.000|阅读 605 次

概述:今天开始学习ASP.NET MVC,在看《ASP.NET MVC架构与实战》时,看到有这样一个组件 RouteMonitor.dll,觉得挺实用的,可以用来检测Url路径的映射匹配情况,只要在浏览器中输入请求地址,就可以得到匹配的情况

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

      今天开始学习ASP.NET MVC,在看《ASP.NET MVC架构与实战》时,看到有这样一个组件 RouteMonitor.dll,觉得挺实用的,可以用来检测Url路径的映射匹配情况,只要在浏览器中输入请求地址,就可以得到匹配的情况,并且以一种友好的页面展现给我们,如下图所示:


图一

于是乎,决定先自己分析一下该原理。

1. 我们都知道一个应用程序启动是从Application_Start事件开始的,在创建一个新的ASP.NET MVC应用程序的时候,默认会在该事件中添加

RegisterRoutes(RouteTable.Routes);

接着RegisterRoutes方法里面编写一些路由映射的方法,将请求的URL映射到相应的控制器中。

2. 现在将Application_Start事件中改写成这样的代码:

1 protected void Application_Start()
2 {
3     RegisterRoutes(RouteTable.Routes);
4     RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes); 
5 }

 

注意到第3行的代码,引用的就是RouteMonitor.dll的组件,通过RouteDebugger的静态方法RewriteRoutesForTesting,并且赋予一个RouteCollection的路由集合的参数,将页面映射到图一的页面,便于查看路由映射的情况。

3. 现在开始分析下RouteMonitor.dll里面都有些什么呢。

里面包含DebugHttpHandler类,DebugRoute类,DebugRouteHandler类,RouteDebugger类,我们先看看RouteDebugger类都做了些什么:
 1 public static class RouteDebugger
 2 {
 3     public static void RewriteRoutesForTesting(RouteCollection routes)
 4     {
 5         //可对路由集合类进行多线程同步访问
 6         using (routes.GetReadLock())
 7         {
 8             bool flag = false;
 9             foreach (RouteBase base2 in routes)
10             {
11   ;              Route route = base2 as Route;
12                 if (route != null)
13                 {
14                 ;    route.RouteHandler = new DebugRouteHandler();
15                 }
16                 if (route == DebugRoute.Singleton)
17                 {
18                     flag = true;
19                 }
20             }
21             if (!flag)
22             {
23                 routes.Add(DebugRoute.Singleton);
24             }
25         }
26     }
27 }


其中routes.GetReadLock()可对路由集合类进行多线程同步访问:

1 public IDisposable GetReadLock()
2 {
3     this._rwLock.AcquireReaderLock(-1);
4     return new ReadLockDisposable(this._rwLock);
5 }

AcquireReaderLock方法去请求得到该读写锁,并且设置超时时间为Infinite(无限),当using方法域结束后将释放该读写锁。

(另:ReaderWriterLock 用于同步对资源的访问。在任一特定时刻,它允许多个线程同时进行读访问,或者允许单个线程进行写访问。在资源不经常发生更改的情况下,ReaderWriterLock 所提供的吞吐量比简单的一次只允许一个线程的锁(如 Monitor)更高。)

接着从routes遍历所有的Route类,在这里我们改变它的路由处理程序,该路由处理程序类的接口为IRouteHandler,用RouteMonitor自带的DebugRouteHandler去替换它原有的RouteHandler,以便后面改变Http处理程序的“方向”。

我们先接着看后面的代码,这里有个routes.Add(DebugRoute.Singleton),DubugRoute继承于Route类,它的构造函数实现于构造可捕获所有URL地址的Route。DebugRoute.Singleton作为单一实例,代码如下:

 1 public class DebugRoute : Route
 2 {
 3     private static DebugRoute singleton = new DebugRoute(); 
 4 
 5     //可捕获所有的URL地址的Route
 6     private DebugRoute()
 7       ;  : base("{*catchall}"new DebugRouteHandler())
 8     {
 9     } 
10 
11     public static DebugRoute Singleton
12     {
13         get
14         {
15    ;         return singleton;
16         }
17     }
18 }

 


4. 接着分析DebugRouteHandler的路由处理程序:

1 public class DebugRouteHandler : IRouteHandler
2 {
3     public IHttpHandler GetHttpHandler(RequestContext requestContext)
4     {
5         DebugHttpHandler handler = new DebugHttpHandler();
6         handler.RequestContext = requestContext;
7         return handler;
8     }
9 }

这样它可以获得实现IHttpHanlder接口的DebugHttpHandler类的实例化对象,这个实例化对象中也传入了一个RequestContext 对象实例。


5. 最后看下这个以IHttpHanlder为接口的DebugHttpHandler类,用于进行Http处理的程序:

 1 public void ProcessRequest(HttpContext context)
 2 {
 3     string format = "<html>\r\n<head>\r\n    <title>路由监测</title>\r\n&nbsp;   <style>\r\n        body, td, th {{font-family: verdana; font-size: .8em;}}\r\n        caption {{font-weight: bold;}}\r\n        tr.header {{background-color: #ffc;}}\r\n        label {{font-weight: bold; }}\r\n    ;    .false {{color: #c00;}}\r\n        .true {{color: #0c0;}}\r\n    </style>\r\n</head>\r\n<body>\r\n<div id=\"main\">\r\n    <p class=\"message\">\r\n        在浏览器中键入请求地址,可以监测匹配的路由。\r\n    </p>\r\n &nbsp;  <p><label>Route</label>: {1}</p>\r\n    <div style=\"float: left;\">\r\n&nbsp;       <table border=\"1\" cellpadding=\"3\" cellspacing=\"0\" width=\"300\">\r\n            <caption>Route Data</caption>\r\n           &nbsp;<tr class=\"header\"><th>Key</th><th>Value</th></tr>\r\n            {0}\r\n&nbsp;       </table>\r\n    </div>\r\n    <div style=\"float: left; margin-left: 10px;\">\r\n      &nbsp; <table border=\"1\" cellpadding=\"3\" cellspacing=\"0\" width=\"300\">\r\n            <caption>Data Tokens</caption>\r\n            <tr class=\"header\"><th>Key</th><th>Value</th></tr>\r\n ;           {4}\r\n        </table>\r\n    </div>\r\n    <hr style=\"clear: both;\" />\r\n  &nbsp;&nbsp;<table border=\"1\" cellpadding=\"3\" cellspacing=\"0\">\r\n      &nbsp; <caption>All Routes</caption>\r\n        <tr class=\"header\">\r\n            <th>Matches Current Request</th>\r\n            <th>Url</th>\r\n            <th>Defaults</th>\r\n&nbsp;           <th>Constraints</th>\r\n            <th>DataTokens</th>\r\n        </tr>\r\n        {2}\r\n    </table>\r\n    <hr />\r\n    <strong>AppRelativeCurrentExecutionFilePath</strong>: {3}\r\n</div>\r\n</body>\r\n</html>";
 4     string str2 = string.Empty; 
 5 
 6     //RouteData类包含所请求路由的相关值
 7   &nbsp; RouteData routeData = this.RequestContext.RouteData; 
 8 
 9     //获得路由的URL参数值和默认值的集合
10     RouteValueDictionary values = routeData.Values; 
11 
12     //获取路由的对象
13     RouteBase base2 ;= routeData.Route; 
14 
15     string str3 = string.Empty;
16     using (RouteTable.Routes.GetReadLock())
17     {
18         foreach (RouteBase base3 in RouteTable.Routes)
19         {
20            &nbsp;//返回有关集合中与指定值匹配的路由的信息,如果为空,说明不匹配
21    &nbsp;        bool flag = base3.GetRouteData(this.RequestContext.HttpContext) != null;
22     &nbsp;   &nbsp;   string str4 = string.Format("<span class=\"{0}\">{0}</span>", flag);
23            &nbsp;string url = "n/a";
24          &nbsp;  string str6 = "n/a";
25   ; &nbsp;        string str7 = "n/a";
26    &nbsp;        string str8 = "n/a";
27       &nbsp;     Route route = base3 as Route; 
28 
29          ;  &nbsp;//如果路由不为空
30  &nbsp;         &nbsp;if (route != null)
31             {
32   &nbsp;             //得到匹配的Url路由
33                 url&nbsp;= route.Url; 
34 
35            &nbsp;    //得到默认的Url匹配规则信息
36                 ;str6 = FormatRouteValueDictionary(route.Defaults);
37         &nbsp;       //得到约束的Url匹配规则信息
38  &nbsp;      ;        str7 = FormatRouteValueDictionary(route.Constraints);
39          &nbsp;      //得到命名空间的Url匹配规则信息
40              ;   str8 = FormatRouteValueDictionary(route.DataTokens);
41             }
42             str3 = str3 + string.Format("<tr&gt;<td&gt;{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{3}</td></tr>"new object[] { str4, url, str6, str7, str8 });
43         }
44     }
45     string str9 = "n/a";
46     string str10 = ""
47 
48     //如果只被{@cacheall}捕获时,提示不匹配
49     if (base2 is DebugRoute)
50     {
51        &nbsp;str9 = "<strong class=\"false\">NO MATCH!</strong>";
52     }
53     else
54     {
55         //匹配的路由信息
56         foreach (string str11 in values.get_Keys())
57         {
58  &nbsp;       ;   str2 = str2 + string.Format("\t<tr><td>{0}</td><td>{1}&amp;nbsp;</td></tr>", str11, values.get_Item(str11));
59         }
60         foreach (string str11 in routeData.DataTokens.get_Keys())
61         {
62          &nbsp;  str10 = str10 + string.Format("\t&lt;tr><td>{0}</td><td>{1}&nbsp;</td></tr>", str11, routeData.DataTokens.get_Item(str11));
63         }
64         Route route2 = base2 as Route;
65         if (route2 != null)
66         {
67             str9 = route2.Url;
68         }
69     }
70     context.Response.Write(string.Format(format, new object[] { str2, str9, str3, context.Request.AppRelativeCurrentExecutionFilePath, str10 }));
71 

 

通过它ProcessRequest来处理请求,最后呈现路由检测的页面。

从中可以看到,首先从RequestContext.RouteData可以得到RouteData类,RouteData类包含所请求路由的相关值。

从RouteData.Values获取路由的 URL 参数值和默认值的集合。

从routeData.Route获取路由的对象。

GetRouteData的方法获取有关集合中与指定值匹配的路由的信息。

通过调用FormatRouteValueDictionary方法得到每一条路由的相关值:

 1 private static string FormatRouteValueDictionary(RouteValueDictionary values)
 2  {
 3      if (values == null)
 4      {
 5    &nbsp;     return "(null)";
 6      }
 7      string str = string.Empty;
 8      //遍历路由键/值对的集合
 9      foreach (string str2 in values.get_Keys())
10      {
11 &nbsp;       &nbsp;str = str + string.Format("{0} = {1}, ", str2, values.get_Item(str2));
12      }
13      if (str.EndsWith(""))
14      {
15  ;        str&nbsp;= str.Substring(0, str.Length - 2);
16      }
17      return str;
18  }

通过重写

context.Response.Write(string.Format(format, new object[] { str2, str9, str3, context.Request.AppRelativeCurrentExecutionFilePath, str10 }));
页面中就呈现出路由匹配的检测信息了。


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn

文章转载自:博客园

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP