Skip to content

Support global endpoint filters and metadata on WebApplication #59755

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
captainsafia opened this issue Jan 7, 2025 · 2 comments
Open

Support global endpoint filters and metadata on WebApplication #59755

captainsafia opened this issue Jan 7, 2025 · 2 comments
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc
Milestone

Comments

@captainsafia
Copy link
Member

captainsafia commented Jan 7, 2025

Background and Motivation

In the past, there have been requests to support adding endpoint filters at the global level (see #43237). More recently, the need for global filters has emerged as part of the work to support a source generator-based validation implementation in minimal APIs (see #46349).

Endpoint filters are implemented on top of ASP.NET Core's conventions API and the IEndpointConventionBuilder. To support global filters, we'll need to expose an API for accessing an underlying IEndpointConventionBuilder on the top-level WebApplication.

Proposed API

// Assembly: Microsoft.AspNetCore
namespace Microsoft.AspNetCore.Builder;

public sealed class WebApplication : IHost, IApplicationBuilder, IEndpointRouteBuilder, IAsyncDisposable
{
+  public IEndpointConventionBuilder Conventions { get; }
}

Usage Examples

var app = WebApplication.Create();

// Register parameter validations for minimal APIs globally
app.Conventions.WithValidation();

// Disable anti-forgery checks on form-based endpoints during development
if (app.Environment.IsDevelopment())
{
  app.Conventions.DisableAntiforgery();
}

// Require authorization on all endpoints in the application
app.Conventions.RequireAuthorization();

app.MapGet("/", () => "Hello world!");

app.Run();

Alternative Designs

Instead of exposing the IEndpointConventionBuilder as a property on the WebApplication class, we can consider implementing the IEndpointConventionBuilder interface directly on the class.

// Assembly: Microsoft.AspNetCore
namespace Microsoft.AspNetCore.Builder;

public sealed class WebApplication : IHost, IApplicationBuilder, IEndpointRouteBuilder, IAsyncDisposable, IEndpointConventionBuilder
{
+  public void Add(Action<EndpointBuilder> convention) { }
+  public void Finally(Action<EndpointBuilder> finallyConvention) { }
}

However, there's hesitation around having WebApplication implement the IEndpointConventionBuilder which is an interface with multiple extension methods (ref) that might pollute the API surface for the WebApplication. Isolating these extension methods to a property keeps the Intellisense on WebApplication clean. On the other hand, there are discoverability questions around the Conventions property.

Alternatively, we can consider exposing a deconstructor on the WebApplication class that allows the user to pull out the underlying IEndpointConventionBuillder.

// Assembly: Microsoft.AspNetCore
namespace Microsoft.AspNetCore.Builder;

public sealed class WebApplication : IHost, IApplicationBuilder, IEndpointRouteBuilder, IAsyncDisposable
{
+  public void Deconstruct(out IEndpointConventionBuilder conventions) { }
}

Risks

  • The name Conventions comes from an implementation details of the framework and is not as familiar to users as related terms like "filter" and "metadata", which map to conventions under the hood. This might impact the discoverability of this feature.
  • Supporting global filters on WebApplication means that users will need to understand the distinction between global middleware and global filters. We'll need to make sure that the distinction is clear to users who might not be familiar with the different pipelines.
  • Since conventions are global and applied to all RouteEndpoints there is a chance that users can use the API in a way that results in non-sensical permutations. For example, a user can invoke app.Conventions.WithGroupName("global") to add a global group name to all endpoints. This concept only makes sense in endpoints that use link-generation or OpenAPI and would be non-sensical of Blazor or SignalR endpoints.
@captainsafia captainsafia added api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc labels Jan 7, 2025
@captainsafia captainsafia self-assigned this Jan 7, 2025
Copy link
Contributor

Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:

  • The PR contains changes to the reference-assembly that describe the API change. Or, you have included a snippet of reference-assembly-style code that illustrates the API change.
  • The PR describes the impact to users, both positive (useful new APIs) and negative (breaking changes).
  • Someone is assigned to "champion" this change in the meeting, and they understand the impact and design of the change.

@halter73 halter73 added this to the 10.0-preview1 milestone Jan 16, 2025
@halter73 halter73 added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews labels Jan 31, 2025
@halter73
Copy link
Member

halter73 commented Jan 31, 2025

API Review Notes:

  • Do we want to pursue global conventions on WebApplication at all?
    • A resounding yes!
  • How noisy would the alternative design of having WebApplication implement IEndpointConventionBuilder be?
    • Very. It would add all the extension methods you see on methods like MapGet()
  • Are we worried that developers will expect these "global" conventions apply to middleware as well as endpoints? For example:
    app.Conventions.RequireAuthorization();
    app.MapStaticAssets(); // Auth required
    app.UseStaticFiles(); // Anonymous requests allowed ¯\_ (ツ)_/¯
    • We are worried, but not enough to do away with the idea of global conventions.
  • What about when user can invoke app.Conventions.WithGroupName("global") to add a global group name to all endpoints? Do we care that this would apply to things like SignalR endpoints too?
    • Not enough to reject the proposal.
  • Can we call it EndpointConventions instead of Conventions to make it clear that it doesn't apply to middleware? Or just Endpoints?
    • EndpointConventions seems like an improvement, because it further clarifies that it applies only to endpoints and not middleware.
  • Could we expose a non-prefixed RouteGroupBuilder on WebApplication.Endpoints?
    • We don't want to have two mostly-equivalent places to call methods like MapGet. We want people to add endpoints directly to WebApplication.
    • We don't want to decide if WebApplication.Endpoints.RequireAuthorization() would apply to all endpoints or just the ones added to the Endpoints property.
  • Do we want an easy way to define conventions that apply to everything added by a given call to UseEndpoints(...)?
    • We're focused on improving WebApplication which we encourage using over UseEndpoints. MapGroup is still a workaround.

API Approved!

// Assembly: Microsoft.AspNetCore
namespace Microsoft.AspNetCore.Builder;

public sealed class WebApplication : IHost, IApplicationBuilder, IEndpointRouteBuilder, IAsyncDisposable
{
+  public IEndpointConventionBuilder EndpointConventions { get; }
}

@captainsafia captainsafia modified the milestones: 10.0-preview1, Backlog Mar 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-approved API was approved in API review, it can be implemented area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc
Projects
None yet
Development

No branches or pull requests

2 participants