Generic or Specific Routes?

A topic of discussion I've heard a few times when using Routing in ASP.NET concerns whether you should use the default generic route pattern for most of your controllers, or whether you should specify individual routes for every action.

(this applies primarily to ASP.NET MVC today, but as routing is likely to be adopted more and more by Web Forms developers too it is a wider question)
The default route pattern looks something like this;

routeCollection.MapRoute(

    "Default",

    "{controller}/{action}/{id}",

    new { controller = "Home",

     action = "Index",

     id = string.Empty });

This means that as soon as I add a new controller to the project, every action is accessible using the default pattern. It also means that the Url pattern is the same for every controller.

After some consideration, and discussions with a few people (the talented Stuart Leeks, and the Web Client Guidance dev team spring to mind) I have to say I've come around to thinking that this is less than ideal.

The alternative is to delete this route definition... and immediately you are forced to add explicit routes for every controller or action that you add. This process makes you think about what Url scheme makes sense for any functionality you add.

A quick example

Let's take a look at some examples to see what this means in practice. I'm using the Web Client Guidance Reference Implementation from p&p – have a look under "~/Initialization/ShellRoutesSupplier.cs" and you'll see where the main application routes are configured. This is part of the Modularity infrastructure in the RI – I'm sure I'll blog about that at some point too, but you can read it in the WCG docs too.

The routes for Search in the RI are as follows;

routeCollection.MapRoute("Search",

    "Search",

    new { controller = "Search", action = "Results" });

routeCollection.MapRoute("SearchActions",

    "Search/{action}/{id}",

    new { controller = "Search", id = (string)null });

What this shows is that the Search controller's main action – "Results" – is accessed using Url patterns something like the following;

https://localhost/Search?query=a

I think this is a very natural Url scheme for a search results page. It is certainly more logical than

https://localhost/Search/Results?query=a

However, the very next route definition sets up a pattern that will match any other action on the Search controller. This is pretty much the equivalent of the default routing scheme. However, the development team have carefully considered the Search controller and decided to expose these actions to support JavaScript functionality. The fact that this consideration has been made is the important point – it isn't a bad thing to expose actions using nice general patterns as long as you've thought about it.

Another set of interesting routes in the RI is for user profiles;

routeCollection.MapRoute("ProfileEdit",

    "Profile/Edit",

    new { controller = "Profile", action = "Edit" });

routeCollection.MapRoute("ProfileView",

    "Profile/{userName}",

    new { controller = "Profile", action = "Show",

          userName = (string)null });

This sets up a route to edit the current users profile, and a nice routing pattern for viewing your friend's profiles, something like this;

https://localhost/Profile/Simon or

https://localhost/Profile/SomeoneElse

You could also have a look at the Top Songs module (under "~/Areas/TopSongs/TopSongsRoutesSupplier.cs") for other examples.

Summary

The bottom line is that I really like this approach of deleting the default route, and considering each action or controller individually.

It enhances the user's experience of your site by providing logical, often short, and easy to follow routes to common functionality. It also contributes to providing a clear perceived structure to your site. It also gives me a feeling of more confidence that sensitive actions are secured and controller code that shouldn't be exposed accidentally isn't (even if this is a little unjustified, and you certainly shouldn't rely on that!).

The trade-off is that you must do this manually for every controller... but having done this in my own code I think this is negligible and well worthwhile.

What approach do you use?

Originally posted by Simon Ince on 31 January 2010 here https://blogs.msdn.com/simonince/archive/2010/01/31/generic-or-specific-routes.aspx