[转载]ASP.NET MVC路由匹配检测组件RouteDebug.dll – Capricornus – 博客园.
以前使用RouteMonitor.dll进行MVC路由检测URL路径的映射匹配情况。由于公司电脑没有此组件,所以上网搜了下,结果才发现RouteMonitor.dll已经将名称改为了RouteDebug.dll 。具体参阅 官方网站。 下载地址:http://files.cnblogs.com/Capricornus/RouteDebug-Binary.zip
使用方法:
1. 在MVC项目中添加引用此组件
2. 在全局应用程序类Global.asax.cs中设置代码
1 |
protected void Application_Start() |
3 |
RegisterRoutes(RouteTable.Routes); |
4 |
RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes); |
3.匹配路由如下图:
我们可以使用Reflector反编译这个RouteDebugger.dll组件,查看一下原理。如图:
RouteDebug中包含了DebugHttpHandler、DebugRoute、DebugRouteHandler、RouteDebugger这4个类。
首先从我们调用RouteDebug.RouteDebugger.RewriteRoutesForTesting的着手。
RouteDebugger类:
01 |
public static class RouteDebugger |
04 |
public static void RewriteRoutesForTesting(RouteCollection routes) |
06 |
using (routes.GetReadLock()) |
09 |
foreach (RouteBase base2 in routes) |
11 |
Route route = base2 as Route; |
14 |
route.RouteHandler = new DebugRouteHandler(); |
16 |
if (route == DebugRoute.Singleton) |
23 |
routes.Add(DebugRoute.Singleton); |
首先,整个代码是使用System.Web.Routing命名空间下的RouteCollection.GetReadLock()锁定的,提供 一个对象,用于管理在从集合中检索对象时的线程安全性;然后遍历我们传过来的路由集合参数。用RouteDebug中的 DebugRouteHandler去替换原有RouteHandler,以便改变Http处理程序的方向,接着将Singletion属性的值添加到路 由结合中。
DebugRoute类:
01 |
public class DebugRoute : Route |
03 |
private static DebugRoute singleton = new DebugRoute(); |
05 |
private DebugRoute() : base ( "{*catchall}" , new DebugRouteHandler()) |
09 |
public static DebugRoute Singleton |
DebugRoute继承与Route类,构造函数实现了构造可捕获所有URL地址的Route。
DebugRouteHandler路由处理程序类:
01 |
public class DebugRouteHandler : IRouteHandler |
04 |
public IHttpHandler GetHttpHandler(RequestContext requestContext) |
06 |
DebugHttpHandler handler = new DebugHttpHandler(); |
07 |
handler.RequestContext = requestContext; |
实现IHttpHanlder接口的实例化对象,传入了一个RequestContext对象实例。
DebugHttpHandler类:
001 |
public class DebugHttpHandler : IHttpHandler |
004 |
private RequestContext <RequestContext>k__BackingField; |
006 |
private static string FormatRouteValueDictionary(RouteValueDictionary values) |
008 |
if ((values == null ) || (values.Count == 0)) |
012 |
string str = string .Empty; |
013 |
foreach ( string str2 in values.Keys) |
015 |
str = str + string .Format( "{0} = {1}, " , str2, values[str2]); |
017 |
if (str.EndsWith( ", " )) |
019 |
str = str.Substring(0, str.Length - 2); |
024 |
public void ProcessRequest(HttpContext context) |
026 |
string str = string .Empty; |
027 |
if (context.Request.QueryString.Count > 0) |
029 |
RouteValueDictionary dictionary = new RouteValueDictionary(); |
030 |
foreach ( string str2 in context.Request.QueryString.Keys) |
032 |
dictionary.Add(str2, context.Request.QueryString[str2]); |
034 |
VirtualPathData virtualPath = RouteTable.Routes.GetVirtualPath( this .RequestContext, dictionary); |
035 |
if (virtualPath != null ) |
037 |
str = "<p><label>Generated URL</label>: " ; |
038 |
str = str + "<strong style=\"color: #00a;\">" + virtualPath.VirtualPath + "</strong>" ; |
039 |
Route route = virtualPath.Route as Route; |
042 |
str = str + " using the route \"" + route.Url + "\"</p>" ; |
046 |
string format = "<html>\r\n<head>\r\n <title>Route Tester</title>\r\n <style>\r\n body, td, th {{font-family: verdana; font-size: small;}}\r\n .message {{font-size: .9em;}}\r\n caption {{font-weight: bold;}}\r\n tr.header {{background-color: #ffc;}}\r\n label {{font-weight: bold; font-size: 1.1em;}}\r\n .false {{color: #c00;}}\r\n .true {{color: #0c0;}}\r\n </style>\r\n</head>\r\n<body>\r\n<h1>Route Tester</h1>\r\n<div id=\"main\">\r\n <p class=\"message\">\r\n Type in a url in the address bar to see which defined routes match it. \r\n A {{*catchall}} route is added to the list of routes automatically in \r\n case none of your routes match.\r\n </p>\r\n <p class=\"message\">\r\n To generate URLs using routing, supply route values via the query string. example: <code>http://localhost:14230/?id=123</code>\r\n </p>\r\n <p><label>Matched Route</label>: {1}</p>\r\n {5}\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 <h3>Current Request Info</h3>\r\n <p>\r\n AppRelativeCurrentExecutionFilePath is the portion of the request that Routing acts on.\r\n </p>\r\n <p><strong>AppRelativeCurrentExecutionFilePath</strong>: {3}</p>\r\n</div>\r\n</body>\r\n</html>" ; |
047 |
string str4 = string .Empty; |
049 |
RouteData routeData = this .RequestContext.RouteData; |
051 |
RouteValueDictionary values = routeData.Values; |
053 |
RouteBase base2 = routeData.Route; |
054 |
string str5 = string .Empty; |
055 |
using (RouteTable.Routes.GetReadLock()) |
057 |
foreach (RouteBase base3 in RouteTable.Routes) |
060 |
bool flag = base3.GetRouteData( this .RequestContext.HttpContext) != null ; |
061 |
string str6 = string .Format( "<span class=\"{0}\">{0}</span>" , flag); |
065 |
string str10 = "n/a" ; |
066 |
Route route2 = base3 as Route; |
072 |
str8 = FormatRouteValueDictionary(route2.Defaults); |
074 |
str9 = FormatRouteValueDictionary(route2.Constraints); |
076 |
str10 = FormatRouteValueDictionary(route2.DataTokens); |
078 |
str5 = str5 + string .Format( "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td></tr>" , new object [] { str6, url, str8, str9, str10 }); |
081 |
string str11 = "n/a" ; |
084 |
if (base2 is DebugRoute) |
086 |
str11 = "<strong class=\"false\">NO MATCH!</strong>" ; |
091 |
foreach ( string str2 in values.Keys) |
093 |
str4 = str4 + string .Format( "\t<tr><td>{0}</td><td>{1} </td></tr>" , str2, values[str2]); |
095 |
foreach ( string str2 in routeData.DataTokens.Keys) |
097 |
str12 = str12 + string .Format( "\t<tr><td>{0}</td><td>{1} </td></tr>" , str2, routeData.DataTokens[str2]); |
099 |
Route route3 = base2 as Route; |
105 |
context.Response.Write( string .Format(format, new object [] { str4, str11, str5, context.Request.AppRelativeCurrentExecutionFilePath, str12, str })); |
108 |
public bool IsReusable |
116 |
public RequestContext RequestContext |
121 |
return this .<RequestContext>k__BackingField; |
126 |
this .<RequestContext>k__BackingField = value; |
通过ProcessRequest方法来处理请求,最后呈现在路由检测的页面上。
首先从RequestContext.RouteData可以得到RouteData类,RouteData类包含所请求路由的相关值。从 RouteData.Values获取路由的URL参数值和默认值集合,在从RouteData.Route获取路由的对象,在获取有关集合中与指定值匹 配的路由信息.