Skip to content

Commit d4927a5

Browse files
Optimize IReportApiVersions DI resolution
1 parent 83c4419 commit d4927a5

File tree

9 files changed

+30
-37
lines changed

9 files changed

+30
-37
lines changed

src/AspNet/WebApi/src/Asp.Versioning.WebApi/DefaultApiVersionReporter.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ public partial class DefaultApiVersionReporter
1212
{
1313
private static DefaultApiVersionReporter? instance;
1414

15-
internal static IReportApiVersions Instance => instance ??= new();
15+
internal static IReportApiVersions GetOrCreate( ISunsetPolicyManager sunsetPolicyManager ) =>
16+
instance ??= new( sunsetPolicyManager );
1617

1718
private static void AddApiVersionHeader( HttpResponseHeaders headers, string headerName, IReadOnlyList<ApiVersion> versions )
1819
{

src/AspNet/WebApi/src/Asp.Versioning.WebApi/DependencyResolverExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal static IApiVersionParser GetApiVersionParser( this IDependencyResolver
1313
resolver.GetService<IApiVersionParser>() ?? ApiVersionParser.Default;
1414

1515
internal static IReportApiVersions GetApiVersionReporter( this IDependencyResolver resolver ) =>
16-
resolver.GetService<IReportApiVersions>() ?? DefaultApiVersionReporter.Instance;
16+
resolver.GetService<IReportApiVersions>() ?? DefaultApiVersionReporter.GetOrCreate( resolver.GetSunsetPolicyManager() );
1717

1818
internal static IControllerNameConvention GetControllerNameConvention( this IDependencyResolver resolver ) =>
1919
resolver.GetService<IControllerNameConvention>() ?? ControllerNameConvention.Default;

src/AspNet/WebApi/test/Asp.Versioning.WebApi.Tests/DefaultApiVersionReporterTest.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ namespace Asp.Versioning;
55
using Asp.Versioning.Simulators;
66
using System.Web.Http;
77
using System.Web.Http.Controllers;
8-
using System.Web.Http.Dependencies;
98
using static System.Net.HttpStatusCode;
109

1110
public class DefaultApiVersionReporterTest
@@ -14,9 +13,8 @@ public class DefaultApiVersionReporterTest
1413
public void report_should_add_expected_headers()
1514
{
1615
// arrange
17-
var reporter = new DefaultApiVersionReporter();
1816
var sunsetDate = DateTimeOffset.Now;
19-
var dependencyResolver = new Mock<IDependencyResolver>();
17+
var reporter = new DefaultApiVersionReporter( new TestSunsetPolicyManager( sunsetDate ) );
2018
var configuration = new HttpConfiguration();
2119
var request = new HttpRequestMessage();
2220
var response = new HttpResponseMessage( OK ) { RequestMessage = request };
@@ -34,9 +32,6 @@ public void report_should_add_expected_headers()
3432
deprecatedAdvertisedVersions: Enumerable.Empty<ApiVersion>() );
3533
var metadata = new ApiVersionMetadata( apiModel, endpointModel, "Test" );
3634

37-
dependencyResolver.Setup( dr => dr.GetService( typeof( ISunsetPolicyManager ) ) )
38-
.Returns( new TestSunsetPolicyManager( sunsetDate ) );
39-
configuration.DependencyResolver = dependencyResolver.Object;
4035
request.SetConfiguration( configuration );
4136
request.ApiVersionProperties().RequestedApiVersion = new ApiVersion( 1.0 );
4237
request.Properties["MS_HttpActionDescriptor"] =

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ private static void Finialize( EndpointBuilder endpointBuilder, ApiVersionSet? v
5252
if ( reportApiVersions )
5353
{
5454
requestDelegate = EnsureRequestDelegate( requestDelegate, endpointBuilder.RequestDelegate );
55-
requestDelegate = new ReportApiVersionsDecorator( requestDelegate, metadata );
55+
56+
var reporter = services.GetRequiredService<IReportApiVersions>();
57+
58+
requestDelegate = new ReportApiVersionsDecorator( requestDelegate, reporter, metadata );
5659
endpointBuilder.RequestDelegate = requestDelegate;
5760
}
5861

src/AspNetCore/WebApi/src/Asp.Versioning.Http/Routing/ReportApiVersionsDecorator.cs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,32 @@
33
namespace Asp.Versioning.Routing;
44

55
using Microsoft.AspNetCore.Http;
6-
using Microsoft.Extensions.DependencyInjection;
76

87
internal sealed class ReportApiVersionsDecorator
98
{
109
private readonly RequestDelegate decorated;
11-
private readonly ApiVersionMetadata metadata;
10+
private readonly IReportApiVersions reporter;
11+
private readonly ApiVersionModel model;
1212

13-
public ReportApiVersionsDecorator( RequestDelegate decorated, ApiVersionMetadata metadata )
13+
public ReportApiVersionsDecorator( RequestDelegate decorated, IReportApiVersions reporter, ApiVersionMetadata metadata )
1414
{
1515
this.decorated = decorated;
16-
this.metadata = metadata;
16+
this.reporter = reporter;
17+
model = metadata.Map( reporter.Mapping );
1718
}
1819

1920
public static implicit operator RequestDelegate( ReportApiVersionsDecorator decorator ) =>
2021
( context ) =>
2122
{
22-
var reporter = context.RequestServices.GetRequiredService<IReportApiVersions>();
23-
var model = decorator.metadata.Map( reporter.Mapping );
2423
var response = context.Response;
25-
26-
response.OnStarting( ReportApiVersions, (reporter, response, model) );
27-
24+
response.OnStarting( ReportApiVersions, (decorator, response) );
2825
return decorator.decorated( context );
2926
};
3027

3128
private static Task ReportApiVersions( object state )
3229
{
33-
var (reporter, response, model) = ((IReportApiVersions, HttpResponse, ApiVersionModel)) state;
34-
reporter.Report( response, model );
30+
var (decorator, response) = ((ReportApiVersionsDecorator, HttpResponse)) state;
31+
decorator.reporter.Report( response, decorator.model );
3532
return Task.CompletedTask;
3633
}
3734
}

src/AspNetCore/WebApi/test/Asp.Versioning.Http.Tests/DefaultApiVersionReporterTest.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ public class DefaultApiVersionReporterTest
1212
public void report_should_add_expected_headers()
1313
{
1414
// arrange
15-
var reporter = new DefaultApiVersionReporter();
1615
var sunsetDate = DateTimeOffset.Now;
16+
var reporter = new DefaultApiVersionReporter( new TestSunsetPolicyManager( sunsetDate ) );
1717
var httpContext = new Mock<HttpContext>();
1818
var features = new Mock<IFeatureCollection>();
1919
var query = new Mock<IQueryCollection>();
@@ -50,7 +50,6 @@ public void report_should_add_expected_headers()
5050
response.SetupGet( r => r.HttpContext ).Returns( () => httpContext.Object );
5151
serviceProvider.Setup( sp => sp.GetService( typeof( IApiVersionParser ) ) ).Returns( ApiVersionParser.Default );
5252
serviceProvider.Setup( sp => sp.GetService( typeof( IApiVersionReader ) ) ).Returns( new QueryStringApiVersionReader() );
53-
serviceProvider.Setup( sp => sp.GetService( typeof( ISunsetPolicyManager ) ) ).Returns( new TestSunsetPolicyManager( sunsetDate ) );
5453
httpContext.SetupGet( c => c.Features ).Returns( features.Object );
5554
httpContext.SetupGet( c => c.Request ).Returns( request.Object );
5655
httpContext.SetupProperty( c => c.RequestServices, serviceProvider.Object );

src/AspNetCore/WebApi/test/Asp.Versioning.Mvc.Tests/ReportApiVersionsAttributeTest.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,14 @@ private static ActionExecutingContext CreateContext(
8181
var actionArguments = new Dictionary<string, object>();
8282
var controller = default( object );
8383
var endpoint = new Endpoint( c => Task.CompletedTask, new( new[] { metadata } ), "Test" );
84+
var options = Options.Create( new ApiVersioningOptions() );
85+
var reporter = new DefaultApiVersionReporter( new SunsetPolicyManager( options ) );
8486

8587
endpointFeature.SetupProperty( f => f.Endpoint, endpoint );
8688
versioningFeature.SetupProperty( f => f.RequestedApiVersion, new ApiVersion( 1.0 ) );
8789
features.Set( endpointFeature.Object );
8890
features.Set( versioningFeature.Object );
89-
serviceProvider.Setup( sp => sp.GetService( typeof( IReportApiVersions ) ) )
90-
.Returns( new DefaultApiVersionReporter() );
91-
serviceProvider.Setup( sp => sp.GetService( typeof( ISunsetPolicyManager ) ) )
92-
.Returns( new SunsetPolicyManager( Options.Create( new ApiVersioningOptions() ) ) );
91+
serviceProvider.Setup( sp => sp.GetService( typeof( IReportApiVersions ) ) ).Returns( reporter );
9392
response.SetupGet( r => r.Headers ).Returns( headers );
9493
response.SetupGet( r => r.HttpContext ).Returns( () => httpContext.Object );
9594
response.Setup( r => r.OnStarting( It.IsAny<Func<object, Task>>(), It.IsAny<object>() ) )

src/Common/src/Common.Mvc/ReportApiVersionsAttribute.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,5 @@ public ReportApiVersionsAttribute() { }
2727
/// Initializes a new instance of the <see cref="ReportApiVersionsAttribute"/> class.
2828
/// </summary>
2929
/// <param name="reportApiVersions">The <see cref="IReportApiVersions">object</see> used to report API versions.</param>
30-
#pragma warning disable CA1019 // Define accessors for attribute arguments
3130
public ReportApiVersionsAttribute( IReportApiVersions reportApiVersions ) => this.reportApiVersions = reportApiVersions;
32-
#pragma warning restore CA1019 // Define accessors for attribute arguments
3331
}

src/Common/src/Common/DefaultApiVersionReporter.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ namespace Asp.Versioning;
77
using HttpResponse = System.Net.Http.HttpResponseMessage;
88
#else
99
using Microsoft.AspNetCore.Http;
10-
using Microsoft.Extensions.DependencyInjection;
1110
#endif
1211
using static Asp.Versioning.ApiVersionMapping;
1312

@@ -23,24 +22,27 @@ public sealed partial class DefaultApiVersionReporter : IReportApiVersions
2322
private const string ApiDeprecatedVersions = "api-deprecated-versions";
2423
private const string Sunset = nameof( Sunset );
2524
private const string Link = nameof( Link );
25+
private readonly ISunsetPolicyManager sunsetPolicyManager;
2626
private readonly string apiSupportedVersionsName;
2727
private readonly string apiDeprecatedVersionsName;
2828

2929
/// <summary>
3030
/// Initializes a new instance of the <see cref="DefaultApiVersionReporter"/> class.
3131
/// </summary>
32+
/// <param name="sunsetPolicyManager">The <see cref="ISunsetPolicyManager">manager</see> used to resolve sunset policies.</param>
3233
/// <param name="supportedHeaderName">The HTTP header name used for supported API versions.
3334
/// The default value is "api-supported-versions".</param>
3435
/// <param name="deprecatedHeaderName">THe HTTP header name used for deprecated API versions.
3536
/// The default value is "api-deprecated-versions".</param>
3637
/// <param name="mapping">One or more of API versioning mappings. The default value is
3738
/// <see cref="ApiVersionMapping.Explicit"/> and <see cref="ApiVersionMapping.Implicit"/>.</param>
3839
public DefaultApiVersionReporter(
40+
ISunsetPolicyManager sunsetPolicyManager,
3941
string supportedHeaderName = ApiSupportedVersions,
4042
string deprecatedHeaderName = ApiDeprecatedVersions,
4143
ApiVersionMapping mapping = Explicit | Implicit )
4244
{
43-
Mapping = mapping;
45+
this.sunsetPolicyManager = sunsetPolicyManager ?? throw new ArgumentNullException( nameof( sunsetPolicyManager ) );
4446

4547
if ( string.IsNullOrEmpty( apiSupportedVersionsName = supportedHeaderName ) )
4648
{
@@ -51,6 +53,8 @@ public DefaultApiVersionReporter(
5153
{
5254
throw new ArgumentNullException( nameof( deprecatedHeaderName ) );
5355
}
56+
57+
Mapping = mapping;
5458
}
5559

5660
/// <inheritdoc />
@@ -86,8 +90,6 @@ public void Report( HttpResponse response, ApiVersionModel apiVersionModel )
8690
return;
8791
}
8892

89-
var name = metadata.Name;
90-
var policyManager = request.GetConfiguration().DependencyResolver.GetSunsetPolicyManager();
9193
var version = request.GetRequestedApiVersion();
9294
#else
9395
var context = response.HttpContext;
@@ -97,14 +99,13 @@ public void Report( HttpResponse response, ApiVersionModel apiVersionModel )
9799
return;
98100
}
99101

100-
var name = metadata.Name;
101-
var policyManager = context.RequestServices.GetRequiredService<ISunsetPolicyManager>();
102102
var version = context.GetRequestedApiVersion();
103103
#endif
104+
var name = metadata.Name;
104105

105-
if ( policyManager.TryGetPolicy( name, version, out var policy ) ||
106-
( !string.IsNullOrEmpty( name ) && policyManager.TryGetPolicy( name, out policy ) ) ||
107-
( version != null && policyManager.TryGetPolicy( version, out policy ) ) )
106+
if ( sunsetPolicyManager.TryGetPolicy( name, version, out var policy ) ||
107+
( !string.IsNullOrEmpty( name ) && sunsetPolicyManager.TryGetPolicy( name, out policy ) ) ||
108+
( version != null && sunsetPolicyManager.TryGetPolicy( version, out policy ) ) )
108109
{
109110
response.WriteSunsetPolicy( policy );
110111
}

0 commit comments

Comments
 (0)