Default route with areas in MVC

By eidias on (tags: area, mvc, route, categories: web)

I stumbled upon a problem when trying to set up a default route for an mvc3 application. The routing mechanism itself is pretty straightforward, so I didn’t really expect any problems here, but as it turned out I was wrong.

Here’s the stripped down version of the problem:

Create a default mvc application – you’ll get the HomeController along with two actions there. Now add a new area (right click on the project and select “Add Area”) – let’s call it “Foo”. In that area, create a controller named “HomeController” and an Index action along with a view for it.

So now we have two Home controllers both with an Index action that simply renders a view.

The route set up by default (in global.asax.cs) looks like this:

   1: routes.MapRoute(
   2:     "Default", // Route name
   3:     "{controller}/{action}/{id}", // URL with parameters
   4:     new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
   5: );

The route set up for the area (FooAreaRegistration.cs) lookans like this:

   1: context.MapRoute(
   2:     "Foo_default",
   3:     "Foo/{controller}/{action}/{id}",
   4:     new { controller = "Home", action = "Index", id = UrlParameter.Optional }
   5: );

I made a small modification to it – added a default value for the controller part (now that I think of it, the controller default value was probably left out on purpose).

Run the app and the problem arises:

   1: 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.
   3: The request for 'Home' has found the following matching controllers:
   4: MvcApplication1.Areas.Foo.Controllers.HomeController
   5: MvcApplication1.Controllers.HomeController

Now this is somewhat weird at first – the url does not have an area prefix, so it should be able to determine which controller to run, but that’s not the case.

I’m not entirely sure why this happens. I’ve tried experimenting with various url schemes including the area itself in the url scheme, but with no luck.

When areas were introduced, they did add the “area” key in RouteData dictionary. It’s value is populated automatically, but I was not able to make it play as I wanted.

The easiest way to get rid of the error is to use different controller names. The second option is to do this:

   1: protected void Application_Start()
   2: {
   3:      AreaRegistration.RegisterAllAreas();
   4:      RegisterRoutes(RouteTable.Routes);
   5:      ControllerBuilder.Current.DefaultNamespaces.Add("RootNamespaceGoesHere.Controllers");
   6: }

Both of these suggestions came from here.

But that’s not the end. What I actually wanted to achieve was to set the area controller as the default one. So when someone typed in the Areas.Foo.Controllers.HomeController would be used instead of the Controllers.HomeController one. And with the second method this actually happened, except that the view being rendered was not the one from Foo area but the one from the ‘root’ area – this would probably be classified as a bug.

The solution

So after struggling with this back and forth I decided to go the KISS way – renamed the root controller from Home to FrontPage and set up the action to redirect to the view I wanted. Maybe not the solution I hoped for, but it works.