using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Template; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Linq; using System.Net; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace CustomMiddlewareExample { public class RouteMatcher { public RouteValueDictionary Match(string routeTemplate, string requestPath, IQueryCollection query) { // The TemplateParser can only parse the route part, and not the query string. // If the template provided by the user also has a query string, we separate that and match it manually. var regex = new Regex(@"(.*)(\?[^{}]*$)"); var match = regex.Match(routeTemplate); if (match.Success) { var queryString = match.Groups[2].Value; routeTemplate = match.Groups[1].Value; var queryInTemplate = QueryHelpers.ParseQuery(queryString); if (!query.All(arg => queryInTemplate.ContainsKey(arg.Key.TrimStart('?')) && queryInTemplate[arg.Key.TrimStart('?')] == arg.Value)) { return null; } } var template = TemplateParser.Parse(routeTemplate); var matcher = new TemplateMatcher(template, GetDefaults(template)); var values = new RouteValueDictionary(); return matcher.TryMatch(requestPath, values) ? values : null; } private RouteValueDictionary GetDefaults(RouteTemplate parsedTemplate) { var result = new RouteValueDictionary(); foreach (var parameter in parsedTemplate.Parameters) { if (parameter.DefaultValue != null) { result.Add(parameter.Name, parameter.DefaultValue); } } return result; } } public class CustomMiddleware { private readonly RequestDelegate _next; public CustomMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { // You can do anything custom here, check the HTTP method, etc. var routeMatcher = new RouteMatcher(); var match = routeMatcher.Match("/my/route/template/{foo}", context.Request.Path, context.Request.Query); if (match == null) { // Route did not match, handle accordingly (return 404, 400, etc.) context.Response.StatusCode = (int)HttpStatusCode.NotFound; } else { // The route was matched, use the args Console.WriteLine("Extracted value: {0}", match["foo"]); context.Response.StatusCode = (int)HttpStatusCode.OK; } } } public class Startup { public void ConfigureServices(IServiceCollection services) { } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseMiddleware<CustomMiddleware>(); } } }