Skip to content

Commit f680ece

Browse files
Refactor to use a default internal container and dependency resolver instead of static singletons
1 parent e29d885 commit f680ece

19 files changed

+160
-78
lines changed

src/AspNet/OData/test/Asp.Versioning.WebApi.OData.Tests/Controllers/VersionedMetadataControllerTest.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public async Task options_should_return_expected_headers()
3737
configuration.AddApiVersioning(
3838
options =>
3939
{
40+
options.ReportApiVersions = true;
4041
options.Policies.Sunset( "VersionedMetadata" )
4142
.Link( "policies" )
4243
.Title( "Versioning Policy" )

src/AspNet/WebApi/src/Asp.Versioning.WebApi.ApiExplorer/ApiExplorer/VersionedApiExplorer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public IDocumentationProvider DocumentationProvider
101101
/// <value>The configured <see cref="ISunsetPolicyManager">sunset policy manager</see>.</value>
102102
protected ISunsetPolicyManager SunsetPolicyManager
103103
{
104-
get => sunsetPolicyManager ??= Configuration.DependencyResolver.GetSunsetPolicyManager();
104+
get => sunsetPolicyManager ??= Configuration.GetSunsetPolicyManager();
105105
set => sunsetPolicyManager = value;
106106
}
107107

@@ -227,7 +227,7 @@ protected virtual ApiDescriptionGroupCollection InitializeApiDescriptions()
227227
}
228228

229229
var routes = FlattenRoutes( Configuration.Routes ).ToArray();
230-
var policyManager = Configuration.DependencyResolver.GetSunsetPolicyManager();
230+
var policyManager = Configuration.GetSunsetPolicyManager();
231231

232232
foreach ( var apiVersion in FlattenApiVersions( controllerMappings ) )
233233
{

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public ApiVersion? RequestedApiVersion
8888
return apiVersion;
8989
}
9090

91-
var parser = request.GetConfiguration().DependencyResolver.GetApiVersionParser();
91+
var parser = request.GetConfiguration().GetApiVersionParser();
9292

9393
try
9494
{

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ namespace Asp.Versioning;
1010
/// </content>
1111
public partial class DefaultApiVersionReporter
1212
{
13-
private static DefaultApiVersionReporter? instance;
14-
15-
internal static IReportApiVersions GetOrCreate( ISunsetPolicyManager sunsetPolicyManager ) =>
16-
instance ??= new( sunsetPolicyManager );
17-
1813
private static void AddApiVersionHeader( HttpResponseHeaders headers, string headerName, IReadOnlyList<ApiVersion> versions )
1914
{
2015
if ( versions.Count == 0 || headers.Contains( headerName ) )
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
namespace Asp.Versioning.Dependencies;
4+
5+
using Asp.Versioning;
6+
using Asp.Versioning.Conventions;
7+
using System.ComponentModel.Design;
8+
using System.Web.Http.Dependencies;
9+
10+
internal sealed class DefaultContainer : IDependencyResolver, IDependencyScope
11+
{
12+
private readonly ServiceContainer container = new();
13+
private bool disposed;
14+
15+
internal DefaultContainer()
16+
{
17+
container.AddService( typeof( ApiVersioningOptions ), static ( sc, t ) => new ApiVersioningOptions() );
18+
container.AddService( typeof( IApiVersionParser ), static ( sc, t ) => ApiVersionParser.Default );
19+
container.AddService( typeof( IControllerNameConvention ), static ( sc, t ) => ControllerNameConvention.Default );
20+
container.AddService( typeof( IProblemDetailsFactory ), static ( sc, t ) => new ProblemDetailsFactory() );
21+
container.AddService( typeof( ISunsetPolicyManager ), NewSunsetPolicyManager );
22+
container.AddService( typeof( IReportApiVersions ), NewApiVersionReporter );
23+
}
24+
25+
public ApiVersioningOptions ApiVersioningOptions
26+
{
27+
get => GetApiVersioningOptions( container );
28+
set
29+
{
30+
container.RemoveService( typeof( ApiVersioningOptions ) );
31+
container.AddService( typeof( ApiVersioningOptions ), value );
32+
}
33+
}
34+
35+
public void Replace( Type serviceType, ServiceCreatorCallback activator )
36+
{
37+
container.RemoveService( serviceType );
38+
container.AddService( serviceType, activator );
39+
}
40+
41+
public IDependencyScope BeginScope() => this;
42+
43+
public void Dispose()
44+
{
45+
if ( disposed )
46+
{
47+
return;
48+
}
49+
50+
disposed = true;
51+
container.Dispose();
52+
}
53+
54+
public object GetService( Type serviceType ) => container.GetService( serviceType );
55+
56+
public IEnumerable<object> GetServices( Type serviceType )
57+
{
58+
var service = container.GetService( serviceType );
59+
60+
if ( service is not null )
61+
{
62+
yield return service;
63+
}
64+
}
65+
66+
private static ApiVersioningOptions GetApiVersioningOptions( IServiceProvider serviceProvider ) =>
67+
(ApiVersioningOptions) serviceProvider.GetService( typeof( ApiVersioningOptions ) );
68+
69+
private static ISunsetPolicyManager NewSunsetPolicyManager( IServiceProvider serviceProvider, Type type ) =>
70+
new SunsetPolicyManager( GetApiVersioningOptions( serviceProvider ) );
71+
72+
private static IReportApiVersions NewApiVersionReporter( IServiceProvider serviceProvider, Type type )
73+
{
74+
var options = GetApiVersioningOptions( serviceProvider );
75+
76+
if ( options.ReportApiVersions )
77+
{
78+
var sunsetPolicyManager = (ISunsetPolicyManager) serviceProvider.GetService( typeof( ISunsetPolicyManager ) );
79+
return new DefaultApiVersionReporter( sunsetPolicyManager );
80+
}
81+
82+
return new DoNotReportApiVersions();
83+
}
84+
}

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

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,39 @@
33
namespace Asp.Versioning;
44

55
using Asp.Versioning.Conventions;
6+
using System.Globalization;
7+
using System.Web.Http;
68
using System.Web.Http.Dependencies;
79

810
internal static class DependencyResolverExtensions
911
{
10-
internal static TService? GetService<TService>( this IDependencyResolver resolver ) => (TService) resolver.GetService( typeof( TService ) );
11-
12-
internal static IApiVersionParser GetApiVersionParser( this IDependencyResolver resolver ) =>
13-
resolver.GetService<IApiVersionParser>() ?? ApiVersionParser.Default;
14-
15-
internal static IReportApiVersions GetApiVersionReporter( this IDependencyResolver resolver ) =>
16-
resolver.GetService<IReportApiVersions>() ?? DefaultApiVersionReporter.GetOrCreate( resolver.GetSunsetPolicyManager() );
17-
18-
internal static IControllerNameConvention GetControllerNameConvention( this IDependencyResolver resolver ) =>
19-
resolver.GetService<IControllerNameConvention>() ?? ControllerNameConvention.Default;
20-
21-
internal static IProblemDetailsFactory GetProblemDetailsFactory( this IDependencyResolver resolver ) =>
22-
resolver.GetService<IProblemDetailsFactory>() ?? ProblemDetailsFactory.Default;
23-
24-
internal static ISunsetPolicyManager GetSunsetPolicyManager( this IDependencyResolver resolver ) =>
25-
resolver.GetService<ISunsetPolicyManager>() ?? SunsetPolicyManager.Default;
12+
internal static TService? GetService<TService>( this IDependencyResolver resolver ) =>
13+
(TService) resolver.GetService( typeof( TService ) );
14+
15+
internal static TService GetRequiredService<TService>( this IDependencyResolver resolver )
16+
{
17+
var service = resolver.GetService<TService>();
18+
var message = string.Format( CultureInfo.CurrentCulture, SR.NoServiceRegistered, typeof( TService ) );
19+
return service ?? throw new InvalidOperationException( message );
20+
}
21+
22+
internal static IApiVersionParser GetApiVersionParser( this HttpConfiguration configuration ) =>
23+
configuration.DependencyResolver.GetService<IApiVersionParser>() ??
24+
configuration.ApiVersioningServices().GetRequiredService<IApiVersionParser>();
25+
26+
internal static IReportApiVersions GetApiVersionReporter( this HttpConfiguration configuration ) =>
27+
configuration.DependencyResolver.GetService<IReportApiVersions>() ??
28+
configuration.ApiVersioningServices().GetRequiredService<IReportApiVersions>();
29+
30+
internal static IControllerNameConvention GetControllerNameConvention( this HttpConfiguration configuration ) =>
31+
configuration.DependencyResolver.GetService<IControllerNameConvention>() ??
32+
configuration.ApiVersioningServices().GetRequiredService<IControllerNameConvention>();
33+
34+
internal static IProblemDetailsFactory GetProblemDetailsFactory( this HttpConfiguration configuration ) =>
35+
configuration.DependencyResolver.GetService<IProblemDetailsFactory>() ??
36+
configuration.ApiVersioningServices().GetRequiredService<IProblemDetailsFactory>();
37+
38+
internal static ISunsetPolicyManager GetSunsetPolicyManager( this HttpConfiguration configuration ) =>
39+
configuration.DependencyResolver.GetService<ISunsetPolicyManager>() ??
40+
configuration.ApiVersioningServices().GetRequiredService<ISunsetPolicyManager>();
2641
}

src/AspNet/WebApi/src/Asp.Versioning.WebApi/Dispatcher/ApiVersionControllerSelector.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ private static void ApplyImplicitConventions( HttpControllerDescriptor controlle
221221
}
222222

223223
var actions = mapping.SelectMany( g => g );
224-
var namingConvention = controller.Configuration.DependencyResolver.GetControllerNameConvention();
224+
var namingConvention = controller.Configuration.GetControllerNameConvention();
225225
var name = namingConvention.GroupName( controller.ControllerName );
226226
var metadata = new ApiVersionMetadata( implicitVersionModel, implicitVersionModel, name );
227227

@@ -344,7 +344,7 @@ private static void ApplyCollatedModelsToActions(
344344
HttpConfiguration configuration,
345345
List<Tuple<HttpControllerDescriptor, HttpActionDescriptor, ApiVersionModel>> visitedActions )
346346
{
347-
var namingConvention = configuration.DependencyResolver.GetControllerNameConvention();
347+
var namingConvention = configuration.GetControllerNameConvention();
348348

349349
for ( var i = 0; i < visitedActions.Count; i++ )
350350
{

src/AspNet/WebApi/src/Asp.Versioning.WebApi/Dispatcher/HttpControllerTypeCache.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ private Dictionary<string, ILookup<string, Type>> InitializeCache()
3333
var services = configuration.Services;
3434
var assembliesResolver = services.GetAssembliesResolver();
3535
var typeResolver = services.GetHttpControllerTypeResolver();
36-
var convention = configuration.DependencyResolver.GetControllerNameConvention();
36+
var convention = configuration.GetControllerNameConvention();
3737
var comparer = StringComparer.OrdinalIgnoreCase;
3838

3939
return typeResolver.GetControllerTypes( assembliesResolver )

src/AspNet/WebApi/src/Asp.Versioning.WebApi/Dispatcher/HttpResponseExceptionFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ internal HttpResponseExceptionFactory( HttpRequestMessage request, ApiVersionMod
3636

3737
private ApiVersioningOptions Options => configuration.GetApiVersioningOptions();
3838

39-
private IProblemDetailsFactory ProblemDetails => configuration.DependencyResolver.GetProblemDetailsFactory();
39+
private IProblemDetailsFactory ProblemDetails => configuration.GetProblemDetailsFactory();
4040

4141
private ITraceWriter TraceWriter => configuration.Services.GetTraceWriter() ?? NullTraceWriter.Instance;
4242

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@ namespace Asp.Versioning;
66

77
internal sealed class DoNotReportApiVersions : IReportApiVersions
88
{
9-
private static DoNotReportApiVersions? instance;
10-
11-
private DoNotReportApiVersions() { }
12-
13-
internal static IReportApiVersions Instance => instance ??= new();
14-
159
public ApiVersionMapping Mapping => Explicit | Implicit;
1610

1711
public void Report( HttpResponseMessage response, ApiVersionModel apiVersionModel ) { }

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public ProblemDetails CreateProblemDetails(
4343
return ProblemDetailsFactory.AddUnsupportedExtensions( request, status, problem, ApplyMessage );
4444
}
4545

46-
return ProblemDetailsFactory.Default.CreateProblemDetails(
46+
return ProblemDetailsFactory.NewProblemDetails(
4747
request,
4848
statusCode,
4949
title,

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@ namespace Asp.Versioning;
1010

1111
internal sealed class ProblemDetailsFactory : IProblemDetailsFactory
1212
{
13-
private static IProblemDetailsFactory? @default;
14-
15-
public static IProblemDetailsFactory Default
16-
{
17-
get => @default ??= new ProblemDetailsFactory();
18-
set => @default = value;
19-
}
20-
2113
public ProblemDetails CreateProblemDetails(
14+
HttpRequestMessage request,
15+
int? statusCode = null,
16+
string? title = null,
17+
string? type = null,
18+
string? detail = null,
19+
string? instance = null ) =>
20+
NewProblemDetails( request, statusCode, title, type, detail, instance );
21+
22+
internal static ProblemDetails NewProblemDetails(
2223
HttpRequestMessage request,
2324
int? statusCode = null,
2425
string? title = null,

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

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,7 @@ public override void OnActionExecuted( HttpActionExecutedContext actionExecutedC
3232

3333
var context = actionExecutedContext.ActionContext;
3434
var action = context.ActionDescriptor;
35-
var reporter = reportApiVersions;
36-
37-
if ( reporter is null )
38-
{
39-
var dependencyResolver = context.ControllerContext.Configuration.DependencyResolver;
40-
reporter = dependencyResolver.GetApiVersionReporter();
41-
}
42-
35+
var reporter = reportApiVersions ?? context.ControllerContext.Configuration.GetApiVersionReporter();
4336
var model = action.GetApiVersionMetadata().Map( reporter.Mapping );
4437

4538
response.RequestMessage ??= actionExecutedContext.Request;

src/AspNet/WebApi/src/Asp.Versioning.WebApi/Routing/ApiVersionRouteConstraint.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public bool Match( HttpRequestMessage request, IHttpRoute route, string paramete
4141
return !string.IsNullOrEmpty( value );
4242
}
4343

44-
var parser = request.GetConfiguration().DependencyResolver.GetApiVersionParser();
44+
var parser = request.GetConfiguration().GetApiVersionParser();
4545
var properties = request.ApiVersionProperties();
4646

4747
properties.RouteParameter = parameterName;

src/AspNet/WebApi/src/Asp.Versioning.WebApi/SR.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/AspNet/WebApi/src/Asp.Versioning.WebApi/SR.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@
161161
<data name="NoControllerSelected" xml:space="preserve">
162162
<value>A controller was not selected for request URI '{0}' and API version '{1}'.</value>
163163
</data>
164+
<data name="NoServiceRegistered" xml:space="preserve">
165+
<value>No service for type '{0}' has been registered.</value>
166+
</data>
164167
<data name="ResourceNotFound" xml:space="preserve">
165168
<value>No HTTP resource was found that matches the request URI '{0}'.</value>
166169
</data>

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

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,10 @@ namespace Asp.Versioning;
88
public partial class SunsetPolicyManager
99
{
1010
private readonly ApiVersioningOptions options;
11-
private static ISunsetPolicyManager? @default;
1211

1312
/// <summary>
1413
/// Initializes a new instance of the <see cref="SunsetPolicyManager"/> class.
1514
/// </summary>
1615
/// <param name="options">The associated <see cref="ApiVersioningOptions">API versioning options</see>.</param>
1716
public SunsetPolicyManager( ApiVersioningOptions options ) => this.options = options;
18-
19-
internal static ISunsetPolicyManager Default
20-
{
21-
get => @default ?? new SunsetPolicyManager( new ApiVersioningOptions() );
22-
set => @default = value;
23-
}
2417
}

0 commit comments

Comments
 (0)