Question

I'm new to Asp.Net MVC, due to some issues I've been having with Routes I discovered Glimpse and thought I'd give it a go, but I couldn't get the Glimpse.axd config page up, constantly getting a HTTP 404.

I made a new project and tried that, it worked fine. Through trial and error I eventually found that the problem is in the AreaRegistration file for my areas, if I do this:

        context.MapRoute(
            "SomeArea_default",
            "Area/{controller}/{action}/{id}",
            new { action = "Index", id = UrlParameter.Optional }

It works, I can get to the page, but if I leave out the area part

        context.MapRoute(
            "SomeArea_default",
            "{controller}/{action}/{id}",
            new { action = "Index", id = UrlParameter.Optional }

then it doesn't.

I have previously asked whether that part was optional and I thought it was: Area routing, why is the area name needed?

I'm putting it back in to get things working, whats the actual reason behind this? Should that always be there or is this a Glimpse bug?

Was it helpful?

Solution

What you are describing is actually normal behavior and has everything to do with the order in which routes are being registered.

Let me explain it, based on a green field project as the one you created to pinpoint the problem.

When you create a new MVC project and you add a Test area for instance, then you'll find the following types and methods inside your project:

  1. A TestAreaRegistration class defined as:

    public class TestAreaRegistration : AreaRegistration 
    {
      public override string AreaName 
      {
        get { return "Test"; }
      }
    
      public override void RegisterArea(AreaRegistrationContext context) 
      {
        context.MapRoute(
          "Test_default",
          "Test/{controller}/{action}/{id}",
          new { action = "Index", id = UrlParameter.Optional }
        );
      }
    } 
    
  2. An Application_Start method inside your global.asax defined as:

    protected void Application_Start()
    {
      AreaRegistration.RegisterAllAreas();
      FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
      RouteConfig.RegisterRoutes(RouteTable.Routes);
      BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
    
  3. A RouteConfig class inside the App_Start folder defined as:

    public class RouteConfig
    {
      public static void RegisterRoutes(RouteCollection routes)
      {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
        routes.MapRoute(
          name: "Default",
          url: "{controller}/{action}/{id}",
          defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
      }
    }
    

Now it is just a matter of reading through the startup code with regards to registering the routes for the application:

  1. First the areas are being registered AreaRegistration.RegisterAllAreas();

  2. That call will result in TestAreaRegistration.RegisterArea(...) being called which will register the route Test/{controller}/{action}/{id}

  3. Then the call to RouteConfig.RegisterRoutes(RouteTable.Routes) will be made which will register the default {controller}/{action}/{id} route and also registers a route to ignore .axd requests.

now it is important to keep in mind that first all routes defined by the Test area will be checked and then the ones defined by the RouteConfig in case it is not a Test area related route

Now what does this mean when you request /glimpse.axd with this default setup ?

The route that will match is the route that is ignored inside the RouteConfig because the routes that will be handled by your Test area must start with Test/ which is clearly not the case for /glimpse.axd

but if you remove the Test/ part from the Test/{controller}/{action}/{id} route registration inside the Test area registration, then the route that will match the /glimpse.axd request will now be handled by the routes defined by the Test area as it will basically act as a catch all, and since it will not find a match a 404 is returned.

TL;DR

Now you can solve this in 2 ways:

  1. Add context.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); to the top of the TestAreaRegistration.RegisterArea method and the route will be ignored like it is in the default situation

  2. Switch the AreaRegistration.RegisterAllAreas(); with the RouteConfig.RegisterRoutes(RouteTable.Routes) so that the RouteConfig routes will be matched first

Personally I would go for option 1 as it has the least impact.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top