A little bit of thinking and compromise can remove unnecessary complexity from the routes in an MVC application.
For example:
Morgan’s web site has authenticated users,and Morgan decides the URLs for managing users should look like /morgan/detail. Morgan adds the following code to register the route:
routes.MapRoute( "User", "{username}/{action}", new { controller ="User", action="Index" } );
Morgan runs some tests and it looks like there is a problem. The User controller is getting requests for /home/index. Oops, that request should have gone to the Home controller. Fortunately, Morgan knows there is all sorts of whizz-bang features you can add to a route, so Morgan creates a route constraint:
public class UserRouteConstraint : IRouteConstraint { public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { var username = values["username"] as string; return IsCurrentUser(username); } private bool IsCurrentUser(string username) { // ... look up the user } }
The constraint prevents the User route from gobbing requests to other controllers. It only allows requests to reach the User controller when the username exists in the application.
Morgan tweaks the route registration code to include the constraint:
routes.MapRoute( "User", "{username}/{action}", new { controller ="User", action="Index"}, new { user = new UserRouteConstraint() } );
Morgan runs some tests and everything works!
Well …
Everything works until a user registers with the name “home”. Morgan goes off to tweak the code again...
As a rule of thumb I try to:
Sometimes you have to go break those rules, but let’s look at Morgan’s case. If Morgan was happy with a URL like /user/index/morgan, then Morgan wouldn’t need to register any additional routes. The default routing entry in a new MVC application would happily invoke the index action of the User controller and pass along the username as the id parameter. Morgan could also go with /user/morgan and use a simple route entry like this:
routes.MapRoute( "User", "User/{username}/{action}", new { controller ="User", action="Index", username="*"} );
No constraints required!
The KISS principle (keep it simple stupid) is a good design principle for routes. You’ll have fewer moving parts, consistent URL structures, and make the code easier to maintain.