Reputation: 710
Perhaps I do not understand correctly how MVC Areas work, but this has got me a little confused.
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.
Upvotes: 5
Views: 1681
Reputation: 1039160
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.
Upvotes: 0
Reputation: 10924
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.
Upvotes: 6
Reputation: 635
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!!
Upvotes: 0