Description
Many metadata-adding extension methods like RequireCors()
, RequireAuthorization()
, WithGroupName()
, etc... can already be applied to an entire group using the GroupRouteBuilder
added in #36007.
However, extension methods like AddFilter
for RouteHandlerBuilder
don't work because GroupRouteBuilder
is not a RouteHandlerBuilder
. This makes it impossible to apply a route handler filter to a group of endpoints today.
Describe the solution you'd like
Originally there was a proposal to add an public void OfBuilder<T>(Action<T> configureBuilder) where T : IEndpointConventionBuilder;
method to GroupRouteBuilder
that would support types like RouteHandlerBuilder
, but that wasn't approved for the initial design. This is partially due to the ugliness of using an Action<T>
to use the RouteHandlerBuilder
and the ugliness of the IGroupEndpointDataSource
interfaces required to support the API.
Now I'm thinking it could be some abstract static interface method on the type implementing IEndpointConventionBuilder (e.g. RouteHandlerBuilder) could construct itself using an arbitrary IEndpointConventionBuilder and rely on EndpiontBuilder.Metadata to keep state.
interface IEndpointConventionBuilderFactory<TSelf>
where T : class, IEndpointConventionBuilder, IEndpointConventionBuilderFactory<TSelf>
{
abstract static T CreateBuilder(IEndpointConventionBuilder builder);
}
// ...
public sealed class RouteHandlerBuilder : IEndpointConventionBuilder, IEndpointConventionBuilderFactory<RouteHandlerBuilder>
{
// ...
// This would be called by GroupRouteBuilder.OfBuilder<T>() or whatever
// with the GroupRouteBuilder as an argument. This should allow returning T
// instead of us relying on on the caller to provide an Action<T> callback.
static RouteHandlerBuilder IEndpointConventionBuilderFactory<RouteHandlerBuilder>.CreateBuilder(IEndpointConventionBuilder builder)
{
return new RouteHandlerBuilder(builder);
}
}
The trick is going to be using EndpointBuilder.Metadata to store the RouteHanderFilterFactories and to read them so it can be rehydrated rather than assuming that the RouteHandlerBuilder returned from the initial call to MapGet/MapPost/etc... is the only RouteHandlerBuilder adding filters to a given endpoint.
Figuring out exactly how we can read the metadata late enough is going to be tough. We need to create a RequestDelegate before adding group metadata given the current design. We might want to build the final handler the first time Endpoint.RequestDelegate is called so we can read the final endpoint metadata off of the HttpContext, then create a new RequestDelegate with all the filters and call that from then on out for the new endpoint. This is probably better than locking routing globally on RequestDelegateFactory.Create like we do today in .NET 7 previews.