Pete
Pete

Reputation: 1867

MVC Area Home displays default Home

I've recently added Areas to an existing MVC 4 web app. One of my areas has a Home controller, so obviously when I navigate to /MyArea/Home/Index I want to display it's Index view. Initially I was getting the following error:

Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.

The request for 'Home' has found the following matching controllers: MyApp.Controllers.HomeController MyApp.Areas.MyArea.Controllers.HomeController

Researching the issue I found that I needed to add default namespaces to my calls to MapRoutes() and that's stopped the error. Unfortunately I now find that when I go to /MyArea/Home/Index the app actually displays the view for /Home/Index instead - I can't display actions from the Area's Home controller.

Here's my code:

Global.aspx.cs

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

MyApp.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},
        namespaces: new[] {typeof(MyApp.Controllers.HomeController).Namespace}
        );
}

MyApp.Areas.MyArea.MyAreaRegistration

public override void RegisterArea(AreaRegistrationContext context)
{
    var ns = typeof(MyApp.Areas.MyArea.Controllers.HomeController).Namespace;

    var routeName = AreaName + "_Route";
    var routeUrl = AreaName + "/{controller}/{action}/{id}";
    var routeDefaults = new {controller = "Home", action = "Index", id = UrlParameter.Optional};
    var routeNamespaces = new[] {ns};

    context.MapRoute(
        name: routeName,
        url: routeUrl,
        defaults: routeDefaults,
        namespaces: routeNamespaces
        );
}

Anyone got any bright ideas on how to solve this?

Update:

The problem only occurs when calling an action that exists in both HomeController classes, like Index. Calling an action in the Area's HomeController that does NOT exist in the default HomeController displays the correct view.

Update 2:

Turns out that this was a classic PICNIC error - a simple typo in my code, so the action went looking for a view that did not exist. As such, it went for the first matching view it could find - the one in the "root"

Upvotes: 0

Views: 1927

Answers (3)

Pete
Pete

Reputation: 1867

<facepalm>

In the process of importing the code for the Area I made a typo in the view's folder name, so MVC wasn't able to find the correct index.cshtml for the area action.

</facepalm>

By the looks of things, when MVC can't find the area action's view it uses the default view instead. Once I'd fixed the name of the folder in Areas\MyArea\Views to match the controller name everything worked as expected.

+1 to both of the folks who answered - your responses were helpful and I've employed both in my updated code

Upvotes: 0

Kevin
Kevin

Reputation: 759

In your RegisterArea function you should update the routeDefaults to also include the area name.

var routeDefaults = new {controller = "Home", action = "Index", area = AreaName, id = UrlParameter.Optional};

Upvotes: 1

user833831
user833831

Reputation: 428

You need to add new { Area = "MyArea" } in the routeValues parameter when you are linking to the one in the MyArea area.

Upvotes: 1

Related Questions