Thursday, March 5, 2015

Route Contraints in MVC5

Since I have been talking about routing in previous two blog posts, so in continuation to that, I decided to talk about route constraints today.

Route Constraint

Route constraint is simply a condition that must be satisfied for the route to match.

Inline Constraints

When using attribute routes we need to use inline constraints. Inline constraints are simple to use. Here is an example:

[Route("Student/{id:int}")]
public ActionResult Details(int id)
{
     return View();
}

Here we tell routing that the matching should be successful only if id is an integer. Similarly, we can use bunch of other data types as constraints like double, bool, etc. Also, we can use constraints like minLength, maxLength, min, max, etc. Their usages are as expected i.e. to specify minimum length, maximum length, minimum value and maximum value, respectively. We also have range constraint to specify a range of values as constraint.

Regular Expression

For more sophisticated scenarios we can even use regular expression like this:

[Route("Account/{id:regex (^a+$)}")]  

Here, the route will match only if the string value contains one or more 'a' characters.

Constraints in Traditional Routing

In traditional routing, we use separate parameter for specifying constraints. Let's take a look at an example.

public static void RegisterRoutes(RouteCollection routes)
{
         routes.MapRoute(
             "student", "{id}",
             new { controller = "student", action = "index" },
             new { id = @"\d{2}" }
         );
}

So here we have specified that the id parameter should be a string containing exactly 2 digits.

Custom Route Constraint

We can even create our own route constraint by implementing IRouteConstraint interface. We need to implement the Match method. Let's take a look at an example:

public class MyDateConstraint : IRouteConstraint
{
       public bool Match(HttpContextBase httpContext, 
       Route route, string parameterName,
       RouteValueDictionary values, 
      RouteDirection routeDirection)
       {
         DateTime dt;
         return DateTime.TryParseExact(
        values[parameterName].ToString(),
        "yyyyMMdd", 
        CultureInfo.InvariantCulture, 
            DateTimeStyles.None, out dt);
        }
}

In the above code, we have written a constraint which checks whether the passed in date is a valid date or not. The route match will be successful only if the date is valid. We can put all sorts of constraints by creating our custom constraints.

Custom Route Constraint in Traditional Routing

In order to use it in traditional routing scenarios, we will need to add an entry to our RouteConfig like this:

public static void RegisterRoutes(RouteCollection routes)
{
       routes.MapRoute(
            name: "customDate",
            url: "{controller}/{action}/{dt}",
            defaults: new { controller = "Student",
              action = "Enrolled" },
            constraints: new { dt = new MyDateConstraint() }
         );
}

So this route match will succeed only if dt is a valid date.

Custom Route Constraint in Attribute Routing

In order to use custom constraints in attribute routes, we will need to first register the constraint like this:

public static void RegisterRoutes(RouteCollection routes)
{
    var constraintsResolver = 
     new DefaultInlineConstraintResolver();
    constraintsResolver.ConstraintMap.Add("myCustomDate", 
                                typeof(MyDateConstraint));
    routes.MapMvcAttributeRoutes(constraintsResolver);
}

Then, we can use it with our action methods like this

[Route("Student/Enrolled/{dt : MyDateConstraint}")]
public ActionResult Enrolled(string dt)
{
       //use dt here    
}

Conclusion

The routing constraints are useful to us when we want to have multiple route entries which are similar but should map to different action methods based on some constraints. Here we saw how to handle such scenarios using traditional routing as well as attribute routing. Then we also saw how to define custom route constraint which can be used for specialized scenarios depending on the application needs.
For future updates to my weekly blog, please subscribe to the blog and follow me on Twitter. Until then Happy Coding :)


References:
"Professional ASP.NET MVC 5"

No comments:

Post a Comment