Design: IEndpointConventionBuilder Extensions Unusable By Other Extensions
See original GitHub issueBackground and Motivation
API Versioning has been investigating support for Minimal APIs per dotnet/aspnet-api-versioning#751. In doing so, it has come to light that the extension methods for IEndpointConventionBuilder are inconsistently implemented and many of them have little-to-no usably by other extensions such as API Versioning.
The primary issues relate to OpenApiRouteHandlerBuilderExtensions.cs. These extensions are very likely to be used by customers in conjunction with API Versioning, but cannot be for the following reasons:
- RouteHandlerBuilder is
sealed
- The extensions methods accept and return the concrete
RouteHandlerBuilder
type
For completeness, a similar problem exists for FallbackEndpointRouteBuilderExtensions.cs. Fallback endpoints are not expected to be used with API Versioning, but it could affect other extensions. These extension methods accept and return IEndpointConventionBuilder, which makes them more usable than OpenApiRouteHandlerBuilderExtensions; however, the lack of passing through a more specific type means that the order setup by developers matters.
The design and implementation of each set of extension methods appears to have been done by different people, at different times, and with different design review considerations.
Proposed API
There doesn’t appear to be a clear reason why these decisions were made. There seems to be no reason to not implement all of the extension methods using the same approach that @JamesNK used in RoutingEndpointConventionBuilderExtensions.cs. This would mean that all extension methods have the form of:
public static TBuilder SomeExtension<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder { }
This approach appears to have been lightly discussed in #8902 previously, which might explain why future extension methods did not follow suite.
The proposed change would benefit not just API Versioning, but any other extension that needs to add/change significant parts of the default Minimal API implementation.
Risks
Changing the signature of the existing APIs are a breaking change, but I believe that adding the intended generic implementations can live side-by-side with the existing non-generic variants.
If the proposal were accepted, when would that happen? As it stands, this issue cascades across APIs. API Versioning would be required to reimplement all of the applicable, existing extension methods to retain feature parity for non-versioned Minimal APIs. Furthermore, the unnecessary non-generic extensions methods have to be retained just as they do in ASP.NET Core - likely forever more. If API Versioning doesn’t reimplement the extensions methods, then there is a feature gap that must be filled by customers.
API Versioning is looking for guidance to achieve the right level of synergy in both the short and long terms.
Example Usage
The tentative design for Minimal APIs for API Versioning will look something like:
app.DefineApi()
.HasVersion(1.0)
.HasVersion(2.0)
.ReportApiVersions()
.HasMapping(api => {
// OpenAPI extensions cannot be used here without reimplementing and maintaining them
api.MapGet("/speak", () => "Hello world!");
api.MapPost("/speak", (string text) => text).MapToApiVersion(2.0);
});
cc: @davidfowl @JamesNK
Issue Analytics
- State:
- Created 2 years ago
- Reactions:2
- Comments:8 (5 by maintainers)
Top GitHub Comments
Maybe it’s okay if the existing overloads
OpenApiRouteHandlerBuilderExtensions
are preferred when given aRouteHandlerBuilder
as long as the new overloads also work on anyIEndpointConventionBuilder
. This means being able to callapp.MapHub<MyHub>("/myhub").Accepts<Person>("application/xml")
which is weird but perhaps the lesser evil.Thanks for contacting us.
We’re moving this issue to the
.NET 8 Planning
milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it’s very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.