user70192
user70192

Reputation: 14224

ASP.NET MVC - Nesting Routes / Controllers

I have an ASP.NET MVC app. I have seen similar question asked. However, I haven't found a good answer. Essentially, I want to use the following routes:

/admin/users
/admin/users/create
/admin/users/[someId]
/admin/roles
/admin/roles/create
/admin/roles/[someId]

I have the following file structure:

/Controllers
  AdminController.cs
  /Admin
    UsersController.cs
    RolesController.cs
/Views
  /Admin
    Index.cshtml
    /Users
      Index.cshtml
      Detail.cshtml
      Create.cshtml
    /Roles
      Index.cshtml
      Create.cshtml
      Detail.cshtml

When I run my app, I just get The resource cannot be found.

What am I doing wrong? I set breakpoints, but none of them are being hit. It's like the routes aren't mapping to the controllers. I'm not sure what I need to do though.

Upvotes: 7

Views: 14128

Answers (3)

NightOwl888
NightOwl888

Reputation: 56909

If you want to use convention (folder) based routing, you could use MvcCodeRouting to do exactly what you have specified here. It uses namespaces by default, so when you add controllers in a hierarchy, it will generate routes in the same hierarchy automatically. No need to apply the [Route] attribute everywhere and setup your routes manually.

Upvotes: 0

Shyju
Shyju

Reputation: 218942

You do not need to create sub folders for this to work. Just have 2 controllers(UsersController and RolesController) and you can use attribute routing to define the custom routing pattern you want.

Assuming you have attribute routing enabled

public class UsersController : Controller
{
  [Route("admin/users")]
  public ActionResult Index()  { // to do : Return something }

  [Route("admin/users/create")]
  public ActionResult Create()  { // to do : Return something }

  [Route("admin/users/{id}")]
  public ActionResult View(int id)  { // to do : Return something }    
}

Or you can do the RoutePrefix on the controller level.

[RoutePrefix("admin/users")]
public class UsersController : Controller
{
  [Route("")]
  public ActionResult Index()  { // to do : Return something }

  [Route("create")]
  public ActionResult Create()  { // to do : Return something }

  [Route("{id}")]
  public ActionResult View(int id)  { // to do : Return something }    
}

You can do the samething for the RolesControllers as well.

You can enable attribute routing in the RegisterRoutes method in RouteConfig.cs file.

public static void RegisterRoutes(RouteCollection routes)
{            
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.MapMvcAttributeRoutes(); //This line enables attribute routing 
   //Existing default Route definition goes here
}

You may also consider creating an "Admin" area and put your controllers inside that. Areas are the right solution if you want to logically group similar functionality.

If you do not prefer attribute routing ( why not ?) , you an define these custom route patterns in your RouteConfig. The order in you define the route matters.So make sure you define your specific routes before the default generic one.

Upvotes: 15

Rick R
Rick R

Reputation: 256

You can also override your route tables by decorating your action methods with the RouteAttribute class.

For example:

class AdminController
{
    [Route("/admin/users/create")]
    public ViewResult CreateUser()
    {
        ...
    }
}

This has the advantage of separating the method name from the url component.

You can also route multiple URLs to a single method:

class AdminController
{
    [Route("/admin/users/{someId:guid}")]
    [Route("/admin/users/{someId:guid}/details")]
    public ViewResult UserDetails(Guid someID)
    {
        ...
    }
}

As mason said, the file structure isn't important in MVC routing.

Upvotes: 1

Related Questions