You can take advantage of custom route constraints in ASP.NET Core to validate route values and avoid passing unwanted or unnecessary requests to action methods. Credit: Thinkstock Route constraints in ASP.NET Core are used to filter out or restrict unwanted data from reaching your controller actions. For a primer on routing in ASP.NET Core, you can refer to my previous article on attribute-based routing versus convention-based routing in ASP.NET Core. This article goes beyond the basics to explore the advanced operations using route constraints. To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here. Create an ASP.NET Core MVC project in Visual Studio 2019 First off, let’s create an ASP.Net Core project in Visual Studio 2019. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new ASP.Net Core project in Visual Studio. Launch the Visual Studio IDE. Click on “Create new project.” In the “Create new project” window, select “ASP.NET Core Web Application” from the list of templates displayed. Click Next. In the “Configure your new project” window, specify the name and location for the new project. Optionally check the “Place solution and project in the same directory” check box, depending on your preferences. Click Create. In the “Create a New ASP.NET Core Web Application” window shown next, select .NET Core as the runtime and ASP.NET Core 3.1 (or later) from the drop-down list at the top. Select “Web Application (Model-View-Controller)” as the project template to create a new ASP.NET Core MVC application. Ensure that the check boxes “Enable Docker Support” and “Configure for HTTPS” are unchecked as we won’t be using those features here. Ensure that Authentication is set to “No Authentication” as we won’t be using authentication either. Click Create. Following these steps will create a new ASP.NET Core MVC project in Visual Studio 2019. We’ll use this project in the sections below to illustrate how we can use route constraints in ASP.NET Core 3.1. The RouteCollection class in ASP.NET Core The RouteTable class in ASP.NET Core contains a property named Routes which stores all routes as RouteCollection. The RouteCollection class contains some extension methods that can be used to map routes or ignore them. MapRoute is an overloaded method that accepts constraints as a parameter. You can use this to pass your constraint to the route. The following is the declaration of the MapRoute method. public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints); The IRouteConstraint interface in ASP.NET Core The IRouteConstraint interface is a contract that contains the declaration of only one method named Match. This interface must be extended by a class and the Match method implemented in it to check if a particular URL parameter is valid for a constraint. Here is how the IRouteConstraint interface is defined: namespace Microsoft.AspNetCore.Routing { public interface IRouteConstraint { bool Match( HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection); } } The ConstraintMap dictionary in ASP.NET Core A ConstraintMap is a dictionary that contains a list of route constraints that maps the route constraint keys to the IRouteConstraint implementations. The code snippet given below illustrates how you can add your custom constraints to this dictionary. public void ConfigureServices(IServiceCollection services) { services.Configure<RouteOptions>(routeOptions => { routeOptions.ConstraintMap.Add("emailconstraint", typeof(EmailRouteContraint)); }); } Implement the IRouteConstraint Match method in ASP.NET Core To create a custom route constraint, you should create a class that extends the IRouteConstraint interface and implements its Match method. The constraint can be used to thwart unwanted incoming requests and prevent a route from being matched unless a particular condition is satisfied. For example, you might want to ensure that the parameter passed to an action method is always an integer. The Match method accepts the following parameters: HttpContext – encapsulates all HTTP specific information about a request IRouter – represents the router that will apply the constraints RouteKey – represents the route parameter that is being validated RouteDirection – an enum that contains two values, namely IncomingRequest and UrlGeneration, and is used to indicate whether the URL is being processed from the HTTP request or generating a URL RouteValues – contains the URL parameters Structure of a custom route constraint in ASP.NET Core Here is an example of the structure of a custom route constraint: public class CustomRouteConstraint : IRouteConstraint { public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { throw new NotImplementedException(); } } Custom route constraint example in ASP.NET Core Let us now implement a custom route constraint that can check for email Ids. First off, create a class that extends the IRouteConstraint interface and implements the Match method. The following code snippet shows a custom route constraint class named EmailRouteContraint that extends the IRouteConstraint interface. public class EmailRouteContraint : IRouteConstraint { public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { return true; } } The following code listing shows the EmailRouteConstraint class with the Match method implemented. public class EmailRouteContraint : IRouteConstraint { public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { if (values.TryGetValue(routeKey, out var routeValue)) { var parameterValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture); return IsEmailAddressValid(parameterValueString); } return false; } private bool IsEmailAddressValid(string emailAddress) { return true; } } Note the IsEmailAddressValid method here simply returns “true.” I leave it up to you to write the necessary code for validating the email address. Register a custom route constraint in ASP.NET Core You should register your custom route constraint with the routing system in the ConfigureServices method of the Startup class. The following code snippet illustrates this. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.Configure<RouteOptions>(routeOptions => { routeOptions.ConstraintMap.Add("ERC", typeof(EmailRouteContraint)); }); } You should also configure your custom route constraint in the Configure method of the Startup class as shown in the code snippet below. app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", constraints: new { ERC = new EmailRouteContraint() }, pattern: "{controller=Home}/{action=Index}/{id?}"); }); And that’s it. You can now specify the constraint in your controller or your action methods and start using the application. The ASP.NET Core runtime validates if the defined pattern and route constraints match the pattern and values of the incoming request. The validation logic of the constraint is defined inside the Match method of your custom route constraint. You can take advantage of constraints to avoid unnecessary requests as well as to validate route values before the request is passed to an action method. How to do more in ASP.NET Core: How to manage user secrets in ASP.NET Core How to build gRPC applications in ASP.NET Core How to redirect a request in ASP.NET Core How to use attribute routing in ASP.NET Core How to pass parameters to action methods in ASP.NET Core MVC How to use API Analyzers in ASP.NET Core How to use route data tokens in ASP.NET Core How to use API versioning in ASP.NET Core How to use Data Transfer Objects in ASP.NET Core 3.1 How to handle 404 errors in ASP.NET Core MVC How to use dependency injection in action filters in ASP.NET Core 3.1 How to use the options pattern in ASP.NET Core How to use endpoint routing in ASP.NET Core 3.0 MVC How to export data to Excel in ASP.NET Core 3.0 How to use LoggerMessage in ASP.NET Core 3.0 How to send emails in ASP.NET Core How to log data to SQL Server in ASP.NET Core How to schedule jobs using Quartz.NET in ASP.NET Core How to return data from ASP.NET Core Web API How to format response data in ASP.NET Core How to consume an ASP.NET Core Web API using RestSharp How to perform async operations using Dapper How to use feature flags in ASP.NET Core How to use the FromServices attribute in ASP.NET Core How to work with cookies in ASP.NET Core How to work with static files in ASP.NET Core How to use URL Rewriting Middleware in ASP.NET Core How to implement rate limiting in ASP.NET Core How to use Azure Application Insights in ASP.NET Core Using advanced NLog features in ASP.NET Core How to handle errors in ASP.NET Web API How to implement global exception handling in ASP.NET Core MVC How to handle null values in ASP.NET Core MVC Advanced versioning in ASP.NET Core Web API How to work with worker services in ASP.NET Core How to use the Data Protection API in ASP.NET Core How to use conditional middleware in ASP.NET Core How to work with session state in ASP.NET Core How to write efficient controllers in ASP.NET Core Related content feature 14 great preprocessors for developers who love to code Sometimes it seems like the rules of programming are designed to make coding a chore. Here are 14 ways preprocessors can help make software development fun again. By Peter Wayner Nov 18, 2024 10 mins Development Tools Software Development feature Designing the APIs that accidentally power businesses Well-designed APIs, even those often-neglected internal APIs, make developers more productive and businesses more agile. By Jean Yang Nov 18, 2024 6 mins APIs Software Development news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages Resources Videos