在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
图一 于是乎,决定先自己分析一下该原理。 1. 我们都知道一个应用程序启动是从Application_Start事件开始的,在创建一个新的ASP.NET MVC应用程序的时候,默认会在该事件中添加 RegisterRoutes(RouteTable.Routes); 接着RegisterRoutes方法里面编写一些路由映射的方法,将请求的URL映射到相应的控制器中。
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 对象实例。
1 public void ProcessRequest(HttpContext context)
2 { 3 string format = "<html>\r\n<head>\r\n <title>路由监测</title>\r\n <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 <p><label>Route</label>: {1}</p>\r\n <div style=\"float: left;\">\r\n <table border=\"1\" cellpadding=\"3\" cellspacing=\"0\" width=\"300\">\r\n <caption>Route Data</caption>\r\n <tr class=\"header\"><th>Key</th><th>Value</th></tr>\r\n {0}\r\n </table>\r\n </div>\r\n <div style=\"float: left; margin-left: 10px;\">\r\n <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 <table border=\"1\" cellpadding=\"3\" cellspacing=\"0\">\r\n <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 <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 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 //返回有关集合中与指定值匹配的路由的信息,如果为空,说明不匹配 21 bool flag = base3.GetRouteData(this.RequestContext.HttpContext) != null; 22 string str4 = string.Format("<span class=\"{0}\">{0}</span>", flag); 23 string url = "n/a"; 24 string str6 = "n/a"; 25 string str7 = "n/a"; 26 string str8 = "n/a"; 27 Route route = base3 as Route; 28 29 //如果路由不为空 30 if (route != null) 31 { 32 //得到匹配的Url路由 33 url = route.Url; 34 35 //得到默认的Url匹配规则信息 36 str6 = FormatRouteValueDictionary(route.Defaults); 37 //得到约束的Url匹配规则信息 38 str7 = FormatRouteValueDictionary(route.Constraints); 39 //得到命名空间的Url匹配规则信息 40 str8 = FormatRouteValueDictionary(route.DataTokens); 41 } 42 str3 = str3 + string.Format("<tr><td>{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 str9 = "<strong class=\"false\">NO MATCH!</strong>"; 52 } 53 else 54 { 55 //匹配的路由信息 56 foreach (string str11 in values.get_Keys()) 57 { 58 str2 = str2 + string.Format("\t<tr><td>{0}</td><td>{1} </td></tr>", str11, values.get_Item(str11)); 59 } 60 foreach (string str11 in routeData.DataTokens.get_Keys()) 61 { 62 str10 = str10 + string.Format("\t<tr><td>{0}</td><td>{1} </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 return "(null)"; 6 } 7 string str = string.Empty; 8 //遍历路由键/值对的集合 9 foreach (string str2 in values.get_Keys()) 10 { 11 str = str + string.Format("{0} = {1}, ", str2, values.get_Item(str2)); 12 } 13 if (str.EndsWith(", ")) 14 { 15 str = 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 }));
|
请发表评论