Phil Haack recently unveiled an improved version of his debugger a few days ago for MVC 3. Incidentally, I had used his source code for the first version to make the same thing for ASP.NET MVC 2. I never thought it was worth releasing because anyone could simply download the RouteDebugger source code and do it themselves. However, since there are bound to be questions on Stack Overflow on how to do this for MVC 2, I thought I’d post the source code here.
The first thing to do is to create a Model class that will house all of the Route information:
public class RouteInformation
{
public string Route { get; set; }
public RouteValueDictionary RouteConstraints { get; set; }
public RouteValueDictionary RouteDataTokens { get; set; }
public RouteValueDictionary RouteDefaults { get; set; }
public RouteValueDictionary RouteValues { get; set; }
public RouteInformation()
{
}
public RouteInformation(HttpContextBase httpContext)
{
var routeData = ((MvcHandler)httpContext.Handler).RequestContext.RouteData;
var routeValues = routeData.Values;
var matchedRouteBase = routeData.Route;
var matchedRoute = matchedRouteBase as Route;
if (matchedRoute != null)
{
Route = matchedRoute.Url ?? string.Empty;
}
AssignRouteValues(httpContext, routeValues);
}
protected virtual VirtualPathData getVirtualPathData(HttpContextBase httpContext, RouteValueDictionary routeValues)
{
return RouteTable.Routes.GetVirtualPath(((MvcHandler)httpContext.Handler).RequestContext, routeValues);
}
private void AssignRouteValues(HttpContextBase httpContext, RouteValueDictionary routeValues)
{
var virtualPathData = getVirtualPathData(httpContext, routeValues);
if (virtualPathData != null)
{
var vpdRoute = virtualPathData.Route as Route;
if (vpdRoute != null)
{
RouteDefaults = vpdRoute.Defaults;
RouteConstraints = vpdRoute.Constraints;
RouteDataTokens = virtualPathData.DataTokens;
RouteValues = routeValues;
}
}
}
}
If the source code for this class looks familiar, it should, it’s refactored directly from the Route Debugger Source code. The next step is to create a ViewModel class for RouteInformation, this class will include all the formatting that’s needed to make it look like this:
Since the View shouldn’t contain logic, all of the view logic is encapsulated in this class (again, just derived from Phil Haack’s source code. Nothing special going on:
public class RouteInformationViewModel
{
public string Route { get; private set; }
public string RouteDefaults { get; private set; }
public string RouteConstraints { get; private set; }
public RouteInformation(Models.RouteInformation routeInformation)
{
RouteConstraints = FormatRouteValues(routeInformation.RouteConstraints);
RouteDataTokens = FormatRouteValues(routeInformation.RouteDataTokens);
RouteDefaults = FormatRouteValues(routeInformation.RouteDefaults);
Route = routeInformation.Route;
}
public string RouteDataTokens { get; private set; }
private static string FormatRouteValues(RouteValueDictionary values)
{
if (values == null || values.Count == 0)
{
return "(null)";
}
StringBuilder result = new StringBuilder();
foreach (string key in values.Keys)
{
result.AppendFormat("{0} = {1}, ", key, values[key]);
}
result.Remove(result.Length - 2, 2);
return result.ToString();
}
}
The final piece two pieces are the ActionResult, and the View:
[ChildActionOnly]
public ActionResult RouteInformation(Member member)
{
var context = HttpContext;
var routeInformation = new Models.RouteInformation(context);
var routeInformationViewModel = new RouteInformationViewModel(routeInformation);
if (member.IsEmployee)
{
return PartialView(routeInformationViewModel);
}
return new EmptyResult();
}
The View (the .ascx):
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Models.ViewModels.RouteInformation>" %>
<h5>Debug Info</h5><p>( Visible Internal Only )</p><ul>
<li>Matched Route: <%= Model.Route %></li>
<li>Route Defaults: <%= Model.RouteDefaults %></li>
<li>Route Constraints : <%= Model.RouteConstraints %></li>
<li>Route DataTokens : <%= Model.RouteDataTokens %></li>
</ul>
That’s all there is to it.