One really nice extensibility point in ASP.NET MVC is the ability to put constraints and write custom constraints on your routes. I tend to think that adding route constraints when possible is a best practice. Why not let the ASP.NET MVC Framework and the routing module take some of the validation burden off of your application when an invalid route value is passed into your application.
Route Constraints
Using route constraints in ASP.NET MVC is part of the process of mapping the routes themselves. Let’s take an example of an e-commerce website that uses a product id in its routes to display products in the product catalog. Since the id has to be an integer in this case and can only be from 1 – 5 digits, let’s specify this as a route constraint so that only these types of id’s are accepted in the route:
routes.MapRoute("Product", "Product/{id}",
new { controller = "Products", action = "Details" },
new { id = @"\d{1,5}" }); // Constraint
Notice how easy it is to specify the id as a range of 1 to 5 digits with a regular expression of “\d{1,5}”. Now if someone enters an invalid route, such as:
/Product/abc
they will receive either a custom error page or the default error page with the message, “the resource cannot be found.”
Custom Route Constraints
Even cooler than using route constraints in ASP.NET MVC is the ability to create custom route constraints. To create a custom route constraint you only have to create a class that implements IRouteConstraint, which only has 1 member to implement, Match.
Let’s create a simple route constraint to limit the acceptable employee names being used as part of a route. The route looks as such:
routes.MapRoute("Employee", "Employee/{name}",
new { controller = "Employees", action="Details" },
new { name = new ExpectedValuesConstraint("john", "jane", "tom") });
Notice the addition of a custom constraint class, called ExpectedValuesConstraint, with a list of names that are expected as values for {name} in the route.
The ExpectedValuesConstraint class implements IRouteConstraint and looks as follows:
public class ExpectedValuesConstraint : IRouteConstraint
{
private readonly string[] _values;
public ExpectedValuesConstraint(params string[] values)
{
_values = values;
}
public bool Match(HttpContextBase httpContext, Route route,
string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
return _values.Contains(values[parameterName].ToString(),
StringComparer.InvariantCultureIgnoreCase);
}
}
In this case, parameterName will be “name”, and then we will just grab the value of the name from the RouteValueDictionary and make sure the name is in the list of values passed into the constructor when the route was mapped. If the name passed in the route does not equal “john”, “jane”, or “tom”, in this case, the user will be taken to the default error page of “the resource cannot be found”.
Conclusion
Anytime you can add a route constraint or custom route constraint to your routes, do so. Let the routing engine help make sure the input to your application is as expected and return errors as appropriate. Note that you can create catch-all routes, etc. when you still want to handle bogus route values in your application. That is for another time.

I agree! I use constraints liberally in my blog, both to catch correct routes with high stringency and to catch invalid routes with great flexibility. I love ASP.NET MVC! My own website and blog run on it.
Posted by: Tim Acheson | 12/12/2009 at 02:28 AM