5

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.

Yannick Blondeau
  • 9,465
  • 8
  • 52
  • 74
Duane
  • 670
  • 1
  • 6
  • 9
  • possible duplicate of [ASP.NET MVC Default routes accessible via area routes](http://stackoverflow.com/questions/4612279/asp-net-mvc-default-routes-accessible-via-area-routes) – Bart Verkoeijen Aug 16 '13 at 04:43

3 Answers3

6

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.

counsellorben
  • 10,924
  • 3
  • 40
  • 38
  • This doesn't seem to work, the Area controller is still being activated via /anarea/ My Controller resides in namespace: TestAreaControllerAccessibleFromGlobal.Areas.MyArea.Controllers, and I added the namespace 'TestAreaControllerAccessibleFromGlobal.Controllers' to the Default route registration (this is where HomeController was put when creating the new project) – Duane Oct 16 '11 at 00:25
  • Do you have any other routes defined in Global.asax.cs? – counsellorben Oct 16 '11 at 00:34
  • No, only the "Default" route with the modifications you suggested in your answer: routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional}, // Parameter defaults null, // constraints new[] { "TestAreaControllerAccessibleFromGlobal.Controllers" } // namespaces ); – Duane Oct 16 '11 at 00:38
  • 1
    The updated solution works, thanks for looking into it. I did think that it was a a bit strange behaviour ... – Duane Oct 16 '11 at 08:28
0

You have to apply a namespace restriction in both area and general route.

In global.asax.cs you should edit RegisterRoutes method just like this

public static void RegisterRoutes(RouteCollection routes)
{
   routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
   routes.MapRoute(
      "Default", 
      "{controller}/{action}/{id}", 
      new { controller = "Home", action = "Index", id = UrlParameter.Optional }, 
      new string[] { "MyProject.Controllers" }
   );
}

That will restrict "//" only to the namespace "MyProject.Controllers"

But also you´ll have to apply the namespace restriction to the Area to restrict "//" only to the namespace "MyProject.Areas.MyArea.Controllers"

For that you´ll have to edit "RegisterArea" method of "MyAreaAreaRegistration.cs" like below ("MyAreaRegistration.cs" is located at "/MyProject/Areas/MyArea" folder ) :

//Some default code stuff
...
public override void RegisterArea(AreaRegistrationContext context)
{
   context.MapRoute(
      "MyArea_default",
      "MyArea/{controller}/{action}/{id}",
      new { action = "Index", id = UrlParameter.Optional },
      new string[] { "MyProject.Areas.MyArea.Controllers" }
   );
}

Hope it helps!!

Lelis718
  • 627
  • 7
  • 16
  • There has to be something missing, I created a new MVC3 project, added a new area called MyArea, made the above changes you suggested but the Area's controller is still visible from global ... i.e. //AreaHome invokes the /MyArea/Controllers/AreaHomeController in namespace "MyProject.Areas.MyArea.Controllers". – Duane Oct 16 '11 at 03:29
0

You seem to be navigating to /AnArea whereas your area is called MyArea so you should navigate to /MyArea/. Here's how the area route registration looks like:

context.MapRoute(
    "MyArea_default",
    "MyArea/{controller}/{action}/{id}",
    new { controller = "AnArea", action = "Index", id = UrlParameter.Optional }
);

AnArea is the name of the controller, not the area. If you want to navigate to some controller of this area you should always prefix your url with MyArea which is the name of the area.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • I understand this, the behaviour that I'm curious about is to how to stop /AnArea/ from resolving to MyArea's AnArea controller. It appears counsellerben has found a solution, so thanks anyways – Duane Oct 16 '11 at 08:25