Skip to content

[Route Groups] Support AddFilter, WithOpenApi and other additive conventions #41427

@halter73

Description

@halter73

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.

Metadata

Metadata

Assignees

Labels

DocsThis issue tracks updating documentationPriority:0Work that we can't release withoutapi-approvedAPI was approved in API review, it can be implementedarea-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcblog-candidateConsider mentioning this in the release blog postfeature-minimal-actionsController-like actions for endpoint routingold-area-web-frameworks-do-not-use*DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions