tags:

views:

193

answers:

6

Simple question!

I'm not asking how to configure routes. I'm asking, given a particular URL, how do I find out for sure which controller action it is being routed to. (Perhaps in the context of a large application with many controllers and a complex route registry.)

A: 

The Controller and Action that are used are determined by the registered routes. Look in your Global.ascx.cs

Here is the default route mapping that comes as standard with a new MVC app. So if your url is http://yourdomain/SomeSiteSection/SomeThing/ then MVC will look for a controller called SomeSiteSectionController and an Action called SomeThing.

public class MvcApplication : System.Web.HttpApplication
{

    //...

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default",                                              // Route name
            "{controller}/{action}/{id}",                           // URL with parameters
            new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
        );

    }

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
    }
}
Daniel Dyson
A: 

It depends on Routes that are registered to resolve the URL

The default conventions is as follows :

public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );

        }

        protected void Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
        }
    }

Index action will be called on HomeController.

Thomas Jaskula
+6  A: 

You could try this ASP.NET Routing Debugger:

alt text

Dan Diplo
+2  A: 

pete,

in code, you can use an actionfilter to determine whats going on:

public class AddUrlInfoToSessionAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!filterContext.HttpContext.Request.IsAjaxRequest())
        {
            // where we are now - do something with the vars in real app
            var currentActionName = filterContext.ActionDescriptor.ActionName;
            var currentControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            var currentRouteData = filterContext.RouteData;
            var currentUrlInfo = new UrlHelper(filterContext.RequestContext);
            string url = RouteTable.Routes.GetVirtualPath(filterContext.RequestContext, currentRouteData.Values).VirtualPath;
        }
    }
}

and then decorate each controller that your interested in as below (or put it onto a basecontroller):

[HandleError]
[AddUrlInfoToSessionAttribute]
public class HomeController : Controller
{
    // controller stuff
}

[AddUrlInfoToSession]
public abstract class BaseController : Controller
{

}

hope this helps

jim

EDIT: just tidied the example up a bit by adding the following to the filter method:

string url = RouteTable.Routes.GetVirtualPath(filterContext.RequestContext, currentRouteData.Values).VirtualPath;

jim
I'm interested in all the controllers.
Pete Montgomery
pete - you'd then have to decorate all the controllers with the [AddUrlInfoToSessionAttribute] flag. this may or not be a big issue depending on the existing codebase. i actually use a more fully featured version of the above code in a few apps in order to keep track of previous route data, so it does work well.
jim
I think in most cases an app would have a generally-used base class, so if that could be relied on then this idea should work... I'll give it a go!
Pete Montgomery
+1  A: 

Something like this for controller:

string controller = RouteData.GetRequiredString("controller");

And for action:

string action = RouteData.GetRequiredString("action");

For example you can use it in your base controller class:

    public class YouControllerBase: Controller
    {
          protected override void Execute(System.Web.Routing.RequestContext requestContext)
          {
              string controller = requestContext.RouteData.GetRequiredString("controller");
              string action = requestContext.RouteData.GetRequiredString("action");
          }
   }

Or use it in global.asax:

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        RouteData routeData = RouteTable.Routes.GetRouteData(
            new HttpContextWrapper(HttpContext.Current));
        var action = routeData.GetRequiredString("action");
    }
Tim
Great thanks - this is simple and useful. The disadvantage is the assumption that every controller reliably inherits from a common base class.
Pete Montgomery
I edited the post. You can use global.asax instead if you don't wish to create base controller class
Tim
A: 

Two simple steps:

  1. Add 2 reference in your project: MvcFakes.dll,RouteDebugger.dll
  2. Entering the following URL: /RouteDebugger

The 2 dlls are contained here:

http://stephenwalther.com/downloads/AspNetMvcUnleashed/Chapter09/Chapter09Code.zip

Chapter09Code.zip\Code\CS\MvcApplication1\MvcApplication1\bin

JP