Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC3 Area controller accessible from global routes?

Perhaps I do not understand correctly how MVC Areas work, but this has got me a little confused.

  1. Add an Area called "MyArea" using right-click "Add Area" in Visual Studio on the MVC3 project
  2. Create a controller for MyArea: "AnArea" with matching view in the MyArea area.
  3. Add "controller = "AnArea" to context.MapRoute's defaults parameter in MyAreaAreaRegistration.RegisterArea method.

So at this point if you start the application and navigate to /MyArea/ it should load the AnArea controller with it's matching view. If you navigate to /MyArea/AnArea, it will show the same result.

But, if you navigate to /AnArea/, the controller is still found and the following error message is displayed:

The view 'Index' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/anarea/Index.aspx
~/Views/anarea/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
~/Views/anarea/Index.cshtml
~/Views/anarea/Index.vbhtml
~/Views/Shared/Index.cshtml
~/Views/Shared/Index.vbhtml

Is this the correct behaviour? I would have thought an area's controller could only be accessed via it's own area and not globally.

like image 264
Duane Avatar asked Oct 15 '11 23:10

Duane


1 Answers

Whenever I create an project with areas, I change my Default route as follows:

    routes.MapRoute( 
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // defaults
        null,  // constraints
        new string[] { "MyApplication.Controllers" } // namespaces
    );

The final parameter limits the default route to the controllers in the MyApplication.Controllers namespace. This insures that the Default route is limited to actions outside of any areas.

UPDATE

After a deep dive into the code, I discovered where the issue arises, and have a solution. Change your Default route to the following:

routes.Add(
    "Default", 
    new Route("{controller}/{action}/{id}",
        new RouteValueDictionary(
            new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        ),
        null,
        new RouteValueDictionary(
            new {
                Namespaces = new string[] { "MyApplication.Controllers" },
                UseNamespaceFallback = false 
            }
        ),
        new MvcRouteHandler()
    )
);

The key is in adding the UseNamespaceFallback token. This will prevent the Default route from looking into any other namespaces.

This is unexpected behavior, and it was a problem I was unaware of which affects a project I am working on. I will list it as an issue at aspnet.codeplex.com. I would not call this a bug, but the behavior definitely appears to breach the convetions for MVC routing.

like image 113
counsellorben Avatar answered Oct 20 '22 13:10

counsellorben