Jamie Rees
Jamie Rees

Reputation: 8183

MVC Routing with different Areas with multiple controllers

My solution structure is the following:

Areas
    - Games
        -Controllers
        -Views etc
    - Movies
        -Controllers
            - MoviesController.cs
            - MovieCalendarController.cs
            - MovieSearchController.cs
        -Views etc

Now what I would like is to be able to do this: Navigate to https://localhost/Movies/ and hit the index of the MoviesController.cs

Navigate to: https://localhost/Movies/Calendar/ and hit the index of the MovieCalendarController.cs

And lastly navigate to https://localhost/Movies/Search/ and hit the index of the MovieSearchController.cs

What I have tried but is not working (getting No route in the route table matches the supplied values.) errors:

MovieAreaRegistration.cs

public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "Movies_default",
                "Movies/{action}/{id}",
                new { controller = "Movies", action = "Index", id = UrlParameter.Optional }
            );

            context.MapRoute(
                "Calendar_default",
                "Movies/Calendar/",
                new { controller = "MovieCalendar", action = "Index", id = UrlParameter.Optional }
            );


            context.MapRoute(
                "Search_default",
                 "Movies/Search/{action}/{id}",
                    new { controller = "MovieSearch", action = "Index", id = UrlParameter.Optional }
            );
        }

Apologies, I'm new to areas and routing

Update

After using attribute routing I have fell into this problem:

Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL.

The request has found the following matching controller types: MovieCalendar.UI.Areas.Movies.Controllers.MovieCalendarController MovieCalendar.UI.Areas.Movies.Controllers.MoviesController

Movies Controller

[RouteArea("Movies")]
[Route("{action}")]
public class MoviesController : BaseController
{
}

Calendar Controller

[RouteArea("Movies")]
[RoutePrefix("Calendar")]
[Route("{action=Index}")]
public class MovieCalendarController : BaseController
{
}

This happens when accessing the url http://localhost/Movies/Calendar hoping it will take me to the MovieCalendarController Index action method. I can see why it's complaining because there could be a ActionMethod in the MovieController called Calendar (There is not).

Upvotes: 7

Views: 6893

Answers (1)

Anish Patel
Anish Patel

Reputation: 4392

You may be better off with Attribute Routing. It will let you do this:

   public class MoviesController : Controller {

        [Route("Movies")]
        public ActionResult Index() {
            return this.View();
        }
    }

    public class MovieCalendarController : Controller {

        [Route("Movies/Calendar")]
        public ActionResult Index() {
            return this.View();
        }
    }

And then you can get rid of your current route mappings and use this initialize your routes:

RouteTable.Routes.MapMvcAttributeRoutes();

More information on attribute routing can be found here.

Update

[RouteArea("Movies")]
[Route("{action}")]
public class MoviesController : BaseController
{
}

This route will match urls starting with Movies/ followed by any string, including Calendar. So this route will clash with:

[RouteArea("Movies")]
[RoutePrefix("Calendar")]
[Route("{action=Index}")]
public class MovieCalendarController : BaseController
{
}

Convention based routing will be difficult with the naming convention your are using for your controllers.

Upvotes: 2

Related Questions