Wednesday, October 1, 2014

Constraints in Attribute Based Routing MVC5

In the previous article we have discussed about the attribute based Routing where the Routes can be specified directly above the Action method or Controller class itself. Now going ahead we will discuss about the Constrained that can be used in the Route.

Constraints are nothing but the validation which we can directly apply on the action methods using the Attribute based routing. With this you also gain the ability to validate your actions more like function overrides, a route will only be matched if the data type matches or the validation we have applied otherwise the request will fall through to the next route matching the pattern, looking for a supported data type.

Some of the common and widely used Constraints are as follows.

Data Type Related

[Route("MyRoute/{x:int}")]  // Matches 32 Bit integer value
public User GetUserById(int id) { ... }

[Route("MyRoute/{x:long}")]  // Matches 64 Bit integer value
public User GetUserById(long id) { ... }

[Route("MyRoute/{x:float}")]  // Matches 32 Bit floating point value
public User GetUserById(float id) { ... }

 [Route("MyRoute/{x:double}")]  // Matches 64 Bit floating point value
public User GetUserById(double id) { ... }

[Route("MyRoute/{x:decimal}")]  // Matches a decimal value
public User GetUserById(decimal id) { ... }

[Route("MyRoute/{x:bool}")]  // Matches a boolean value
public User GetUserByCondition(bool id) { ... }

[Route("MyRoute/{x:guid}")] // Matches a Unique Identifier value
public User GetUserById(GUID id) { ... }

[Route("MyRoute/{x:datetime}")]  // Matches a datetime value
public User GetUserByIdLoginTime(datetime id) { ... }

String Related Constraints 

[Route("MyRoute/{x:alpha}")]  // Matches upper and lower case value from a-z
public User GetUserByName(string id) { ... }
[Route("MyRoute/{x:length(5)}")]  // Matchesstring value with specified length
public User GetUserByName(string id) { ... }
[Route("MyRoute/{x:length(2,100)}")]  // Matches string value with specified length range
public User SetUserByName(string id) { .. }

[Route("MyRoute/{x:minlength(8)}")]  // Matches a string with minimum specified length
public User SetUserByName(string id) { ... }

[Route("MyRoute/{x:maxlength(20)}")]  // Matches a string value with specified maximum length
public User SetUserByName(string id) { ... }

Other Common Constraints

[Route("MyRoute/{x:min(1)}")]  // Matches integer value with minimum specified value
public Product GetAmount(int id) { ... }

[Route("MyRoute/{x:max (100)}")]  // Matches integer with specified maximum value
public Product GetAmount(int id) { ... }

[Route("MyRoute/{x:range(1, 100)}")]  // Matches integer with specified range of value
public Product GetProducts(int id) { ... }

[Route("MyRoute/{x:regex(^[a-z][0-9]$)}")]  // Matches value with specified regular expression
public Product GetProducts(int id) { ... }

[Route("QuerystringParameterExists?{X})]  // Matched Query string parameter if it exist or not
public Product GetProducts(int id) { ... }

[Route("QuerystringParameterConstraints{x:int}&{y:int}")]  // Matched Query string parameter if they are of specified type or not
public Product GetProducts(int id) { ... }

Custom Route Constraints

You can create custom route constraints by implementing the IHttpRouteConstraint interface. For example, the following constraint restricts a parameter to a set of predefined values.

public class CorrectConstraint: IRouteConstraint
   private readonly string[] correctOptions;
   public CorrectConstraint(string strOptions)
        correctOptions = strOptions.Split('#');

p        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
                 object value;
                 if (values.TryGetValue(parameterName, out value) && value != null)
                  return correctOptions.Contains(value.ToString(), StringComparer.OrdinalIgnoreCase);
                  return false;

     To register this value in the Constraint we have to add the code in the Route config as below.

      public static void RegisterRoutes(RouteCollection routes)
        var constraintsResolver = new DefaultInlineConstraintResolver();
        constraintsResolver.ConstraintMap.Add("values", typeof(ValuesConstraint));

And the Route can be called as  below.

     public class BusinessController : Controller
             public ActionResult Show(string scale)
                 return Content("Valid set of value is " + scale);

Hope you now Understand that how the constraints in the Attribute based route can be used and applied and how can we create a custom base Route.  Please feel free to provide your valuable comment on the same.

Thanks & Regards
Anil Kumar Pandey
Microsoft MVP, Microsoft MCC, DNS MVM