Skip to content

Commit f1f7042

Browse files
Ensure service scopes are preserved
1 parent aa8bb4c commit f1f7042

1 file changed

Lines changed: 59 additions & 3 deletions

File tree

src/AspNetCore/WebApi/src/Asp.Versioning.Http/Builder/EndpointBuilderFinalizer.cs

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,11 @@ private static void Finialize( EndpointBuilder endpointBuilder, ApiVersionSet? v
7676

7777
endpointBuilder.RequestDelegate = context =>
7878
{
79-
context.RequestServices = new InjectApiVersion( context );
79+
if ( context.RequestServices is not InjectApiVersion )
80+
{
81+
context.RequestServices = new InjectApiVersion( context );
82+
}
83+
8084
return requestDelegate( context );
8185
};
8286
}
@@ -282,11 +286,12 @@ private record struct ApiVersionBuckets(
282286
&& AdvertisedDeprecated.Count == 0;
283287
}
284288

285-
private sealed class InjectApiVersion : IServiceProvider, IKeyedServiceProvider
289+
private sealed class InjectApiVersion : IKeyedServiceProvider, IServiceScopeFactory
286290
{
287-
private static readonly Type ApiVersionType = typeof( ApiVersion );
288291
private readonly IServiceProvider provider;
289292
private readonly HttpContext context;
293+
internal static readonly Type ApiVersionType = typeof( ApiVersion );
294+
internal static readonly Type ServiceScopeFactoryType = typeof( IServiceScopeFactory );
290295

291296
public InjectApiVersion( HttpContext context )
292297
{
@@ -295,6 +300,10 @@ public InjectApiVersion( HttpContext context )
295300
context.RequestServices = this;
296301
}
297302

303+
#pragma warning disable CA2000 // Dispose objects before losing scope
304+
public IServiceScope CreateScope() => new ApiVersionScope( context, provider.CreateScope() );
305+
#pragma warning restore CA2000
306+
298307
public object? GetKeyedService( Type serviceType, object? serviceKey ) =>
299308
provider.GetKeyedService( serviceType, serviceKey );
300309

@@ -307,8 +316,55 @@ public object GetRequiredKeyedService( Type serviceType, object? serviceKey ) =>
307316
{
308317
return context.RequestedApiVersion;
309318
}
319+
else if ( serviceType.Equals( ServiceScopeFactoryType ) )
320+
{
321+
return this;
322+
}
310323

311324
return provider.GetService( serviceType );
312325
}
313326
}
327+
328+
private sealed class ApiVersionScope( HttpContext context, IServiceScope scope )
329+
: IKeyedServiceProvider, IServiceScopeFactory, IServiceScope
330+
{
331+
private bool disposed;
332+
333+
public IServiceProvider ServiceProvider => this;
334+
335+
#pragma warning disable CA2000 // Dispose objects before losing scope
336+
public IServiceScope CreateScope() => new ApiVersionScope( context, scope.ServiceProvider.CreateScope() );
337+
#pragma warning restore CA2000
338+
339+
public object? GetKeyedService( Type serviceType, object? serviceKey ) =>
340+
scope.ServiceProvider.GetKeyedService( serviceType, serviceKey );
341+
342+
public object GetRequiredKeyedService( Type serviceType, object? serviceKey ) =>
343+
scope.ServiceProvider.GetRequiredKeyedService( serviceType, serviceKey );
344+
345+
public object? GetService( Type serviceType )
346+
{
347+
if ( serviceType.IsAssignableFrom( InjectApiVersion.ApiVersionType ) )
348+
{
349+
return context.RequestedApiVersion;
350+
}
351+
else if ( serviceType.Equals( InjectApiVersion.ServiceScopeFactoryType ) )
352+
{
353+
return this;
354+
}
355+
356+
return scope.ServiceProvider.GetService( serviceType );
357+
}
358+
359+
public void Dispose()
360+
{
361+
if ( disposed )
362+
{
363+
return;
364+
}
365+
366+
disposed = true;
367+
scope.Dispose();
368+
}
369+
}
314370
}

0 commit comments

Comments
 (0)