Open gfoidl opened 5 hours ago
I just found in https://github.com/dotnet/aspnetcore/issues/38468 that there exists an interface IParameterLiteralNodeMatchingPolicy
.
I implemented constrain:
public class UniqueRouteConstraint : IRouteConstraint, IParameterLiteralNodeMatchingPolicy
{
public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values,
RouteDirection routeDirection)
{
return true;
}
public bool MatchesLiteral(string parameterName, string literal)
{
return false;
}
}
and registered it
services.AddRouting(options =>
{
options.ConstraintMap.Add("unique", typeof(UniqueRouteConstraint));
});
This seems to solve my issue.
But question remains why router behaves like that? Is it intentional or it is a backward compatibility with ASP MVC? Also note that decorating each "{param}"
with "{param:unique}
" to avoid this behavior is quite tedious...
CC @javiercn since you introduced IParameterLiteralNodeMatchingPolicy
in https://github.com/dotnet/aspnetcore/issues/35042
However I would like param to be anything and /first/second return "First".
This will never match the path /first
But question remains why router behaves like that? Is it intentional or it is a backward compatibility with ASP MVC? Also note that decorating each "{param}" with "{param:unique}" to avoid this behavior is quite tedious...
This is intentional, the two routes on the original example will match different things.
/first can only match the first route
,
/first/second can only match the second route
The optimization that we did implies that you will never want to match /first/second
to the second route, but that would result in a 404, not in matching /first
.
If you want to match /first/second
then you are stuck with
app.MapGet("/first", () => "First");
app.MapGet("/{param}/second", () => "Second");
Our routing algorithm trades-off memory for CPU time so that matching is always linear based on the number of segments in the path.
I would add though that it's not easy to run into this case (for the vast majority of apps we've seen it's fine) so you shouldn't be trying to apply this technique unless you actually have a problem.
Also, if you wanted to apply this technique programmatically, there are ways to do so, like using an endpoint builder convention to programmatically modify the routes, for example based on the parameter name.
Discussed in https://github.com/dotnet/aspnetcore/discussions/58837