I'm working on an ASP.NET Core application where I have a default route template,
for example: ~/api/{area}/[controller]/{action?}/{id?}.
My goal is to match incoming URLs with other route templates and dynamically reconstruct them with the default route template when no direct match is found.
Consider a scenario where someone sends a request like ~/{area}/api/[controller]/{action?}/{id?}. The first call to app.UseRouting(), EndpointRoutingMiddleware doesn't find any match.
In such cases, I want to rebuild the path dynamically to match my default route template (~/api/{area}/[controller]/{action?}/{id?}) and then trigger app.UseRouting() again to find the correct endpoint.
Startup.cs;
app.UseRouting();
app.UseMiddleware<RoutingMatcherMiddleware>();
app.UseRouting();
Middleware;
public Task Invoke(HttpContext context)
{
var endpointFeature = context.Features[typeof(IEndpointFeature)] as IEndpointFeature;
var endpoint = endpointFeature?.Endpoint;
if (endpoint != null)
{
return _next(context);
}
//My other route templates that I didn't define on my BaseApiController
foreach (var routeTemplate in _routeTemplates)
{
var templateParser = TemplateParser.Parse(routeTemplate);
var matcher = new TemplateMatcher(templateParser, null);
var values = new RouteValueDictionary();
if (matcher.TryMatch(context.Request.Path, values))
{
context.Request.Path = ReBuildRequestPath(context.Request.Path, values);
break;
}
}
return _next(context);
}
But this logic doesn't work properly since the second UseRouting overrides the request pipeline and the first one is completely ignored. And situation causes that endpoint is always null here;
if (endpoint != null)
{
return _next(context);
}
In sum, my custom matcher is executed for every request regardless it is matched with my default template or not.
Same problem mentioned here as well;
https://github.com/dotnet/aspnetcore/issues/17210
Any idea about alternative solutions/ideas ?
Note: I am restricted to define all possible route templates on my BaseApiController due to performance issue on .NET 5 and this is why I am looking for a dynamic solution;