Before we dig into the topic, let's just peek into the EndpointDataSource collection which groups routes and can be examined at runtime:
app.MapGet( "/debug/endpoints",
async ( IEnumerable<EndpointDataSource> dataSources ) =>
{
var list = new List<object>();
foreach ( var dataSource in dataSources )
{
foreach ( var endpoint in dataSource.Endpoints )
{
if ( endpoint is RouteEndpoint routeEndpoint )
{
// Wyciągamy metadane (np. nasz WymaganyPoziomDostepu, HttpMethodMetadata itp.)
var httpMethodMeta = endpoint.Metadata.GetMetadata<HttpMethodMetadata>();
var methods = httpMethodMeta?.HttpMethods != null
? string.Join(", ", httpMethodMeta.HttpMethods)
: "ANY";
list.Add( new
{
DisplayName = endpoint.DisplayName,
RoutePattern = routeEndpoint.RoutePattern.RawText,
Methods = methods,
MetadataCount = endpoint.Metadata.Count
} );
}
}
}
return Results.Ok( list );
} );
Now, both Endpoint Filters and Route Constrains can be used to add constraints to matched routes.
An Endpoint Filter is attached to the endpoint and acts as kind of a "wrapper", it can add custom filtering, call the actual request delegate and modify the result:
app.MapGet( "/rf/{id:int}", (int id) => $"rf: {id}" ).AddEndpointFilter( async ( context, next ) =>
{
var id = context.GetArgument<int>(0);
if ( id < 10 )
{
return Results.BadRequest();
}
Console.WriteLine( "before request delegate call" );
// call actual delegate
var result = await next( context );
Console.WriteLine( "after request delegate call" );
// you can modify the result
return result;
} );
On the other hand, a custom Route Constraint can add a finetuned filtering to route parameters:
public class MyCustomConstraint : IRouteConstraint
{
public bool Match(
HttpContext? httpContext,
IRouter? route,
string routeKey,
RouteValueDictionary values,
RouteDirection routeDirection )
{
if ( values.TryGetValue( routeKey, out var value ) && value is string stringValue )
{
// accept only strings starting with "cust" and longer than 5 chars
return stringValue.StartsWith( "cust" ) && stringValue.Length > 5;
}
return false;
}
}
...
builder.Services.Configure<RouteOptions>( options =>
{
options.ConstraintMap.Add( "customconstraint", typeof( MyCustomConstraint ) );
} );
...
app.MapGet( "/cc/{id:customconstraint}", ( string id ) => $"cc: {id}" );
| Route Constraint | Endpoint Filter | |
|---|---|---|
| What for? | Decision: match this endpoint | Action: custom code around the endpoint |
| When? | Early, decides which endpoint should be selected | Late, endpoint is already selected |
| Scope? | Tiny, only specific segment in the route template like {id:customconstraint} | Whole endpoint |
| Has access to what? | Only raw url parameter values | Full access to HttpContext, arguments and the result |
| Does what? | Returns true/false - match the endpoint or skip | Can modify the result, skip processing and/or add custom code before and after |
No comments:
Post a Comment