@@ -6,13 +6,10 @@ namespace Microsoft.AspNetCore.Builder;
66
77using Asp . Versioning ;
88using Asp . Versioning . ApiExplorer ;
9- using Asp . Versioning . OpenApi ;
109using Asp . Versioning . OpenApi . Internal ;
1110using Microsoft . AspNetCore . Builder ;
12- using Microsoft . AspNetCore . OpenApi ;
13- using Microsoft . AspNetCore . Routing ;
11+ using Microsoft . AspNetCore . Http ;
1412using Microsoft . Extensions . DependencyInjection ;
15- using System . Diagnostics . CodeAnalysis ;
1613
1714/// <summary>
1815/// Provides extension methods for <see cref="IEndpointConventionBuilder"/>.
@@ -32,91 +29,27 @@ public static class IEndpointConventionBuilderExtensions
3229 /// <returns>The original <see cref="IEndpointConventionBuilder">endpoint convention builder</see>.</returns>
3330 public IEndpointConventionBuilder WithDocumentPerVersion ( )
3431 {
35- builder . Finally ( new WithoutRecursion ( ) . Run ) ;
32+ builder . Finally ( ApplyApiVersioning ) ;
3633 return builder ;
3734 }
3835 }
3936
40- // This is a workaround to prevent infinite recursion when applying API versioning conventions to the OpenAPI
41- // endpoint, which occurs because IApiVersionDescriptionProviderFactory.Create calls back into the endpoint's
42- // RequestDelegate to resolve the IApiVersionDescriptionProvider, which causes the conventions to be applied again.
43- private sealed class WithoutRecursion
44- {
45- private bool recursed ;
46-
47- public void Run ( EndpointBuilder builder )
48- {
49- if ( recursed )
50- {
51- return ;
52- }
53-
54- recursed = true ;
55- ApplyApiVersioning ( builder ) ;
56- recursed = false ;
57- }
58- }
59-
6037 private static void ApplyApiVersioning ( EndpointBuilder builder )
6138 {
6239 if ( builder . RequestDelegate is { } action )
6340 {
64- #pragma warning disable CA2000 // Dispose objects before losing scope
65- var requestServices = NewRequestServices ( builder . ApplicationServices ) ;
66- #pragma warning restore CA2000 // Dispose objects before losing scope
67-
68- builder . RequestDelegate = context =>
69- {
70- context . RequestServices = requestServices ;
71- return action ( context ) ;
72- } ;
41+ builder . RequestDelegate = context => InterceptRequestServices ( context , action ) ;
7342 }
7443 }
7544
76- [ UnconditionalSuppressMessage ( "ILLink" , "IL3050" ) ]
77- private static KeyedServiceContainer NewRequestServices ( IServiceProvider services )
45+ private static Task InterceptRequestServices ( HttpContext context , RequestDelegate action )
7846 {
79- var configure = services . GetRequiredKeyedService < Action < ApiVersionDescription , OpenApiOptions > > ( typeof ( ApiVersion ) ) ;
80- var factory = services . GetRequiredService < IApiVersionDescriptionProviderFactory > ( ) ;
81- var sources = services . GetRequiredService < ConfigureOpenApiOptions > ( ) . DataSources ;
82- var keyedServices = new KeyedServiceContainer ( services ) ;
83- var names = new List < string > ( ) ;
84- IApiVersionDescriptionProvider provider ;
85-
86- if ( sources . Count == 0 )
47+ if ( context . RequestServices is not KeyedServiceContainer requestServices )
8748 {
88- provider = factory . Create ( ) ;
89- }
90- else
91- {
92- using var source = new CompositeEndpointDataSource ( sources ) ;
93- provider = factory . Create ( source ) ;
94- }
95-
96- foreach ( var description in provider . ApiVersionDescriptions )
97- {
98- names . Add ( description . GroupName ) ;
99- keyedServices . Add ( Type . OpenApiSchemaService , description . GroupName , Class . OpenApiSchemaService . New ) ;
100- keyedServices . Add ( Type . OpenApiDocumentService , description . GroupName , Class . OpenApiDocumentService . New ) ;
101- keyedServices . Add (
102- typeof ( IOpenApiDocumentProvider ) ,
103- description . GroupName ,
104- ( sp , k ) => sp . GetRequiredKeyedService ( Type . OpenApiDocumentService , k ) ) ;
105- }
106-
107- if ( names . Count > 0 )
108- {
109- var array = Array . CreateInstance ( Type . NamedService , names . Count ) ;
110-
111- for ( var i = 0 ; i < names . Count ; i ++ )
112- {
113- array . SetValue ( Class . NamedService . New ( names [ i ] ) , i ) ;
114- }
115-
116- keyedServices . Add ( Type . IDocumentProvider , Class . OpenApiDocumentProvider . New ) ;
117- keyedServices . Add ( Type . IEnumerableOfNamedService , array ) ;
49+ requestServices = context . RequestServices . GetRequiredService < KeyedServiceContainer > ( ) ;
11850 }
11951
120- return keyedServices ;
52+ context . RequestServices = requestServices ;
53+ return action ( context ) ;
12154 }
12255}
0 commit comments