Custom Routing Constraint In ASP.NET Core


Constraint Usages 

  1. It helps to avoid the unnecessary requests on url where we are restricted to route value pattern. Let’s say – in action parameter, only integer values are allowed; so except integers, all the requests are rejected by the route constraint and a 404 (Page not found ) response is returned to users.
  2. To validate the route values : – routing constraint validates the incoming requests before passing them to Controller action.

IRouteConstraint interface

It defines the contract that a class must implement in order to check whether a URL parameter value is valid for a constraint or not.

This interface contains only single API in order to match the constrains.  

The Match method has 5 parameters . Let’s discuss each, in details.

  1. HttpContext encapsulates all http specific information about an http request like request, response, sessions, and more. You can check the httpcontext as well if the request is authenticated or not, and take the appropriate action accordingly.
  2. IRouter is the router which belongs to constraints.
  3. RouteKey is the name of the parameter that is being checked. The same name is defined in route template.
  4. Routevalues contain the parameters of the URL.
  5. RouteDirection indicates whether ASP.NET routing is processing a URL from an HTTP request or generating a URL. This is an enum class that has two directions.
    1. IncomingRequest
      A URL from a client is being processed.
    2. UrlGeneration
      A URL is being created based on the route definition.

ConstraintMap

It is a key value pair dictionary which contains the list of route constraints. The routing framework adds the list of default constraints with their types. You can learn more about default constraints here on github.

https://github.com/aspnet/Routing/blob/dev/src/Microsoft.AspNetCore.Routing/RouteOptions.cs#L41-L71

You have to add custom route constraint in this dictionary with the help of route options.Let’s take an example of creating alphanumeric route constraints. This example is just for demonstration purposes; there are many ideas to use the constraints. You can use the regex constraints in case of any pattern matching.

Here, I’m going to create an alphanumeric constraint which checks if the incoming request parameter contains alphanumeric value or not.

Alphanumeric route constraint is implemented from the IRouteConstraint interface.

  1. public class AlphaNumericConstraint : IRouteConstraint  
  2.     {  
  3.         private static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(10);  
  4.   
  5.         public bool Match(HttpContext httpContext,   
  6.             IRouter route,   
  7.             string routeKey,   
  8.             RouteValueDictionary values,   
  9.             RouteDirection routeDirection)  
  10.         {  
  11.             //validate input params  
  12.             if (httpContext == null)  
  13.                 throw new ArgumentNullException(nameof(httpContext));  
  14.   
  15.             if (route == null)  
  16.                 throw new ArgumentNullException(nameof(route));  
  17.   
  18.             if (routeKey == null)  
  19.                 throw new ArgumentNullException(nameof(routeKey));  
  20.   
  21.             if (values == null)  
  22.                 throw new ArgumentNullException(nameof(values));  
  23.   
  24.             object routeValue;  
  25.   
  26.             if(values.TryGetValue(routeKey, out routeValue))  
  27.             {  
  28.                 var parameterValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture);  
  29.                 return new Regex(@”^[a-zA-Z0-9]*$”,   
  30.                                 RegexOptions.CultureInvariant   
  31.                                 | RegexOptions.IgnoreCase, RegexMatchTimeout).IsMatch(parameterValueString);  
  32.             }  
  33.   
  34.             return false;  
  35.         }  
  36.     }  

I have alphanumeric regex to check the incoming request parameter that contains the a-z or 0-9.  

Add your constraint into ConstraintMap using route option in configure services method in the startup class. Here, you have to add route key with the type which is created above.

  1. public void ConfigureServices(IServiceCollection services)  
  2.         {  
  3.             // Add framework services.  
  4.             services.AddMvc();  
  5.   
  6.             // add here your route constraint   
  7.             services.Configure<RouteOptions>(routeOptions =>   
  8.             {  
  9.                 routeOptions.ConstraintMap.Add(“alphanumeric”, typeof(AlphaNumericConstraint));  
  10.             });  
  11.         }   

Add your constraint in route template here. You have to use “:” seperator in between route parameter and constraints. The format looks like  {parameter name: route constraint name }.

  1. app.UseMvc(routes =>  
  2.             {  
  3.                 routes.MapRoute(  
  4.                     name: “default”,  
  5.                     template: “{controller=Home}/{action=Index}/{id:alphanumeric}”);  
  6.             });