RouteDebugger分析

RouteDebugger的介绍  http://www.cnblogs.com/suizhikuo/archive/2012/07/25/2608889.html

2.RouteDebugger结构,一共有5个文件,将逐一解释每个文件的作用

RouteDebug.cs

using System.Web.Routing;



namespace RouteDebug

{

    public class DebugRoute : Route

    {

        static readonly DebugRoute singleton = new DebugRoute();



        public static DebugRoute Singleton

        {

            get { return singleton; }

        }



        private DebugRoute()

            : base("{*catchall}", new DebugRouteHandler()) { }

    }

}

全局单例的DebugRoute,构造函数传入了DebugRouteHandler。

 

DebugRouteHandler.cs

using System.Web;

using System.Web.Routing;



namespace RouteDebug

{

    public class DebugRouteHandler : IRouteHandler

    {

        public IHttpHandler GetHttpHandler(RequestContext requestContext)

        {

            return new DebugHttpHandler();

        }

    }

}

核心都在DebugHttpHandler最后再解释。

 

PreApplicationStart.cs

using System;

using System.Configuration;

using System.Web;

using RouteDebug;



[assembly: PreApplicationStartMethod(typeof(PreApplicationStart), "Start")]



namespace RouteDebug

{

    public class PreApplicationStart

    {

        public static void Start()

        {

            bool enabled = Convert.ToBoolean(ConfigurationManager.AppSettings["RouteDebugger:Enabled"]);

            if (enabled)

            {

                Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(RouteDebuggerHttpModule));

            }

        }

    }

}

项目启动时利用DynamicModuleUtility根据Webconfig配置动态的注册RouteDebuggerHttpModule.

 

RouteDebuggerHttpModule.cs

namespace RouteDebug

{

    public class RouteDebuggerHttpModule : IHttpModule

    {

        public void Init(HttpApplication context)

        {

            context.EndRequest += OnEndRequest;

            context.BeginRequest += OnBeginRequest;

        }



        static void OnBeginRequest(object sender, System.EventArgs e)

        {

            if (RouteTable.Routes.Last() != DebugRoute.Singleton)

            {

                RouteTable.Routes.Add(DebugRoute.Singleton);

            }

        }



        static void OnEndRequest(object sender, System.EventArgs e)

        {

            var handler = new DebugHttpHandler();



            handler.ProcessRequest(HttpContext.Current);

        }



        public void Dispose()

        {

        }

    }

}

OnBeginRequest向路由表添加DebugRoute.

OnEndRequest输出RouteDebugger信息.

 

DebugHttpHandler.cs

using System;

using System.Collections.Generic;

using System.Reflection;

using System.Web;

using System.Web.Hosting;

using System.Web.Routing;



namespace RouteDebug

{

    public class DebugHttpHandler : IHttpHandler

    {

        readonly VirtualPathProvider _virtualPathProvider;



        public DebugHttpHandler() : this(null) { }



        public DebugHttpHandler(VirtualPathProvider virtualPathProvider)

        {

            _virtualPathProvider = virtualPathProvider ?? HostingEnvironment.VirtualPathProvider;

        }



        public void ProcessRequest(HttpContext context)

        {

            var request = context.Request;



            if (!IsRoutedRequest(request) || context.Response.ContentType == null || !context.Response.ContentType.Equals("text/html", StringComparison.OrdinalIgnoreCase))

            {

                return;

            }



            string generatedUrlInfo = string.Empty;

            var requestContext = request.RequestContext;



            if (request.QueryString.Count > 0)

            {

                var rvalues = new RouteValueDictionary();

                foreach (string key in request.QueryString.Keys)

                {

                    if (key != null)

                    {

                        rvalues.Add(key, request.QueryString[key]);

                    }

                }



                var vpd = RouteTable.Routes.GetVirtualPath(requestContext, rvalues);

                if (vpd != null)

                {

                    generatedUrlInfo = "<p><label style=\"font-weight: bold; font-size: 1.1em;\">Generated URL</label>: ";

                    generatedUrlInfo += "<strong style=\"color: #00a;\">" + vpd.VirtualPath + "</strong>";

                    var vpdRoute = vpd.Route as Route;

                    if (vpdRoute != null)

                    {

                        generatedUrlInfo += " using the route \"" + vpdRoute.Url + "\"</p>";

                    }

                }

            }



            const string htmlFormat = @"<html>

<div id=""haackroutedebugger"" style=""background-color: #fff; padding-bottom: 10px;"">

    <style>

        #haackroutedebugger, #haackroutedebugger td, #haackroutedebugger th {{background-color: #fff; font-family: verdana, helvetica, san-serif; font-size: small;}}

        #haackroutedebugger tr.header td, #haackroutedebugger tr.header th {{background-color: #ffc;}}

    </style>

    <hr style=""width: 100%; border: solid 1px #000; margin:0; padding:0;"" />

    <h1 style=""margin: 0; padding: 4px; border-bottom: solid 1px #bbb; padding-left: 10px; font-size: 1.2em; background-color: #ffc;"">Route Debugger</h1>

    <div id=""main"" style=""margin-top:0; padding: 0 10px;"">

        <p style=""font-size: .9em; padding-top:0"">

            Type in a url in the address bar to see which defined routes match it. 

            A {{*catchall}} route is added to the list of routes automatically in 

            case none of your routes match.

        </p>

        <p style=""font-size: .9em;"">

            To generate URLs using routing, supply route values via the query string. example: <code>http://localhost:14230/?id=123</code>

        </p>

        <p><label style=""font-weight: bold; font-size: 1.1em;"">Matched Route</label>: {1}</p>

        {5}

        <div style=""float: left;"">

            <table border=""1"" cellpadding=""3"" cellspacing=""0"" width=""300"">

                <caption style=""font-weight: bold;"">Route Data</caption>

                <tr class=""header""><th>Key</th><th>Value</th></tr>

                {0}

            </table>

        </div>

        <div style=""float: left; margin-left: 10px;"">

            <table border=""1"" cellpadding=""3"" cellspacing=""0"" width=""300"">

                <caption style=""font-weight: bold;"">Data Tokens</caption>

                <tr class=""header""><th>Key</th><th>Value</th></tr>

                {4}

            </table>

        </div>

        <hr style=""clear: both;"" />

        <table border=""1"" cellpadding=""3"" cellspacing=""0"">

            <caption style=""font-weight: bold;"">All Routes</caption>

            <tr class=""header"">

                <th>Matches Current Request</th>

                <th>Url</th>

                <th>Defaults</th>

                <th>Constraints</th>

                <th>DataTokens</th>

            </tr>

            {2}

        </table>

        <hr />

        <h3>Current Request Info</h3>

        <p>

            AppRelativeCurrentExecutionFilePath is the portion of the request that Routing acts on.

        </p>

        <p><strong>AppRelativeCurrentExecutionFilePath</strong>: {3}</p>

    </div>

</div>";

            string routeDataRows = string.Empty;



            var routeData = requestContext.RouteData;

            var routeValues = routeData.Values;

            var matchedRouteBase = routeData.Route;



            string routes = string.Empty;

            using (RouteTable.Routes.GetReadLock())

            {

                foreach (var routeBase in RouteTable.Routes)

                {

                    bool matchesCurrentRequest = (routeBase.GetRouteData(requestContext.HttpContext) != null);

                    string matchText = string.Format(@"<span{0}>{1}</span>", BoolStyle(matchesCurrentRequest), matchesCurrentRequest);

                    string url = "n/a";

                    string defaults = "n/a";

                    string constraints = "n/a";

                    string dataTokens = "n/a";



                    Route route = CastRoute(routeBase);



                    if (route != null)

                    {

                        url = route.Url;

                        defaults = FormatDictionary(route.Defaults);

                        constraints = FormatDictionary(route.Constraints);

                        dataTokens = FormatDictionary(route.DataTokens);

                    }



                    routes += string.Format(@"<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td></tr>"

                            , matchText

                            , url

                            , defaults

                            , constraints

                            , dataTokens);

                }

            }



            string matchedRouteUrl = "n/a";



            string dataTokensRows = "";



            if (!(matchedRouteBase is DebugRoute))

            {

                foreach (string key in routeValues.Keys)

                {

                    routeDataRows += string.Format("\t<tr><td>{0}</td><td>{1}&nbsp;</td></tr>", key, routeValues[key]);

                }



                foreach (string key in routeData.DataTokens.Keys)

                {

                    dataTokensRows += string.Format("\t<tr><td>{0}</td><td>{1}&nbsp;</td></tr>", key, routeData.DataTokens[key]);

                }



                var matchedRoute = matchedRouteBase as Route;



                if (matchedRoute != null)

                    matchedRouteUrl = matchedRoute.Url;

            }

            else

            {

                matchedRouteUrl = string.Format("<strong{0}>NO MATCH!</strong>", BoolStyle(false));

            }



            context.Response.Write(string.Format(htmlFormat

                , routeDataRows

                , matchedRouteUrl

                , routes

                , request.AppRelativeCurrentExecutionFilePath

                , dataTokensRows

                , generatedUrlInfo));

        }



        private Route CastRoute(RouteBase routeBase)

        {

            var route = routeBase as Route;

            if (route == null)

            {

                // cheat!

                // TODO: Create an interface for self reporting routes.

                var type = routeBase.GetType();

                var property = type.GetProperty("__DebugRoute", BindingFlags.NonPublic | BindingFlags.Instance);

                if (property != null)

                {

                    route = property.GetValue(routeBase, null) as Route;

                }

            }

            return route;

        }



        private static string FormatDictionary(IDictionary<string, object> values)

        {

            if (values == null)

                return "(null)";



            if (values.Count == 0)

            {

                return "(empty)";

            }



            string display = string.Empty;

            foreach (string key in values.Keys)

            {

                display += string.Format("{0} = {1}, ", key, FormatObject(values[key]));

            }

            if (display.EndsWith(", "))

                display = display.Substring(0, display.Length - 2);

            return display;

        }



        private static string FormatObject(object value)

        {

            if (value == null)

            {

                return "(null)";

            }



            var values = value as object[];

            if (values != null)

            {

                return string.Join(", ", values);

            }



            var dictionaryValues = value as IDictionary<string, object>;

            if (dictionaryValues != null)

            {

                return FormatDictionary(dictionaryValues);

            }



            if (value.GetType().Name == "UrlParameter")

            {

                return "UrlParameter.Optional";

            }



            return value.ToString();

        }



        private static string BoolStyle(bool boolean)

        {

            if (boolean) return " style=\"color: #0c0\"";

            return " style=\"color: #c00\"";

        }



        private bool IsRoutedRequest(HttpRequest request)

        {

            string path = request.AppRelativeCurrentExecutionFilePath;

            if (path != "~/" && (_virtualPathProvider.FileExists(path) || _virtualPathProvider.DirectoryExists(path)))

            {

                return false;

            }

            return true;

        }



        public bool IsReusable

        {

            get { return true; }

        }

    }

}

 

IHttpHandler接口肯定都不陌生,有两个地方会调用到ProcessRequest方法。一是RouteDebuggerHttpModule的EndRequest方法。二是匹配到DebugRoute,DebugRoute加在了路由表的最后,没有匹配到任何的Route的时候就会返回DebugRoute。 所以这个时候就会输出两次ProcessRequest. 这是RouteDebugger的核心,循环RouteTable.Routes判断是否匹并且输出。

你可能感兴趣的:(debugger)