As you might already know if you’re using ASP.NET MVC, routing is how ASP.NET MVC matches a URI to an Action within a Controller. In the unlikely case you don’t know what I’m talking about, I strongly suggest you to read this great ASP.NET MVC Controller Overview by Stephen Walther before going further: if you keep reading, I’ll just assume you know such basic MVC-related stuff.
Now, a common problem in ASP.NET MVC development is the fact that, when you have a lot of controllers, your application project could become a bit messy: you’ll soon start to feel the need to organize them under Namespaces, which will also bring in the urge to group them into separate subfolders in order to organize them properly. Eventually, you’ll also want to have their URL to reflect that folder structure: if you end up having a /Admin/Dashboard/MainController in your project, you’ll most likely want to have a meaningful URL for it such as the following:
Now, ASP.NET MVC default routing is built upon the DefaultControllerFactory class, which ignores the subfolders inside the root /Controllers/ folder. In other words, it will traverse all controllers under the “Controller” folder and creates a cache using just the class name as the key, thus ignoring any namespace or any subfolder where you have put the controller.
If you want to create a route which takes the subfolders into account, you have to do one of the following things:
- Create a new ControllerFactory that will check if the requested controller belongs to any specific namespace and/or subfolder. Such method is well explained in this post, yet I wouldn’t personally recommend it as it’s not required (see below).
- Add a new global route using the routes.MapRoute() method in your project’s /App_Start/RouteConfig.cs file, as explained in this StackOverflow thread. This is definitely a viable approach, yet I wouldn’t do that as well (see below).
- Take advantage of the ASP.NET Attribute Routing Feature, firstly introduced in MVC 5 and then re-implemented (with small differences) in ASP.NET MVC 6 / ASP.NET Core as well (I wrote a post on it a while ago).
The latter approach is by far my preferred one, since it’s dead simple to implement – it only takes a couple lines of source code. The Attribute Routing feature, as the name implies, is a technique that allows you to define routes using attributes, thus giving you more control over the URIs in your web application. It blends fine with the “earlier” style of routing, called convention-based routing, to the point you can even combine both techniques in the same project. As a matter of fact, you kinda have to, unless you don’t want to “attribute-route” everything!
Here’s how you can implement Attribute Routing in your project: let’s take the previous example for granted, assuming you have a /Admin/Dashboard/MainController.cs controller file which you want to respond to the /Admin/Dashboard/Main/ URL requests.
#1: Enable Attribute Routing in your App
The first thing to do is to activate the Attribute Routing feature within your app: doing that is as easy as adding the following highlighted line to your project’s /App_Start/RouteConfig.cs file:
public class RouteConfig
public static void RegisterRoutes(RouteCollection routes)
// IMPORTANT: put this *BEFORE* any convention-based routing rule
// other routes.MapRoute() settings
As the comment says, it’s very important to put the routes.MapMvcAttributeRoutes() call before any other convention-based routing rule.
#2: Add the [Route] Attribute
As soon as you enabled the Attribute Routing feature, you can start decorating your Controllers with the [Route] attribute in the following way:
// TODO: Place the Controller's Actions Methods here.
// They will all respond to /Admin/Dashboard/Main/ActionName requests
As the comment implies, the Action Methods within the above controller will respond to the /Admin/Dashboard/Main/ActionName request URL.
For further info about MVC 5 Attribute Routing feature, I strongly suggest to take a look at this official Microsoft post, which is full of useful samples about that new routing model.
That’s it for now… happy routing!