Skip to content

Commit b9fd3b4

Browse files
Refactor to hide access to services that will be available via EndpointBuilder.ServiceProvider and minimize breaking changes in 7.0
1 parent 531a81e commit b9fd3b4

File tree

11 files changed

+100
-156
lines changed

11 files changed

+100
-156
lines changed

src/AspNetCore/WebApi/src/Asp.Versioning.Http/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/AspNetCore/WebApi/src/Asp.Versioning.Http/SR.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@
123123
<data name="ConventionAddedAfterEndpointBuilt" xml:space="preserve">
124124
<value>Conventions cannot be added after building the endpoint.</value>
125125
</data>
126+
<data name="NoEndpointBuilderServices" xml:space="preserve">
127+
<value>The required services have not been provided to the EndointBuilder.</value>
128+
</data>
126129
<data name="RequestTypeUnconfigured" xml:space="preserve">
127130
<value>The request type was not configured.</value>
128131
</data>

src/AspNetCore/WebApi/src/Asp.Versioning.Http/net6.0/Builder/ApiVersionSet.cs

Lines changed: 6 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,21 @@
22

33
namespace Asp.Versioning.Builder;
44

5-
using Microsoft.Extensions.Options;
6-
using Opts = Microsoft.Extensions.Options.Options;
7-
85
/// <summary>
96
/// Represents an API version set.
107
/// </summary>
118
public class ApiVersionSet
129
{
13-
private readonly IOptions<ApiVersioningOptions> options;
14-
15-
/// <summary>
16-
/// Initializes a new instance of the <see cref="ApiVersionSet"/> class.
17-
/// </summary>
18-
/// <param name="builder">The associated <see cref="ApiVersionSetBuilder">builder</see>.</param>
19-
/// <param name="name">The optional API name.</param>
20-
/// <param name="parameterSource">The configured <see cref="IApiVersionParameterSource">API version
21-
/// parameter source</see>.</param>
22-
/// <param name="options">The configured <see cref="ApiVersioningOptions">API versioning options</see>.</param>
23-
public ApiVersionSet(
24-
ApiVersionSetBuilder builder,
25-
string? name,
26-
IApiVersionParameterSource parameterSource,
27-
ApiVersioningOptions options ) :
28-
this( builder, name, parameterSource, Opts.Create( options ) )
29-
{
30-
}
31-
3210
/// <summary>
3311
/// Initializes a new instance of the <see cref="ApiVersionSet"/> class.
3412
/// </summary>
3513
/// <param name="builder">The associated <see cref="ApiVersionSetBuilder">builder</see>.</param>
3614
/// <param name="name">The optional API name.</param>
37-
/// <param name="parameterSource">The configured <see cref="IApiVersionParameterSource">API version
38-
/// parameter source</see>.</param>
39-
/// <param name="options">The configured <see cref="ApiVersioningOptions">API versioning options</see>.</param>
40-
public ApiVersionSet(
41-
ApiVersionSetBuilder builder,
42-
string? name,
43-
IApiVersionParameterSource parameterSource,
44-
IOptions<ApiVersioningOptions> options )
15+
public ApiVersionSet( ApiVersionSetBuilder builder, string? name )
4516
{
4617
Builder = builder ?? throw new ArgumentNullException( nameof( builder ) );
4718
Name = name;
4819
ReportApiVersions = builder.WillReportApiVersions;
49-
ParameterSource = parameterSource;
50-
this.options = options;
5120
}
5221

5322
/// <summary>
@@ -62,17 +31,9 @@ public ApiVersionSet(
6231
/// <value>True if all APIs in the version set will report their API versions; otherwise, false.</value>
6332
public bool ReportApiVersions { get; }
6433

65-
/// <summary>
66-
/// Gets the configured API version parameter source.
67-
/// </summary>
68-
/// <value>The configured <see cref="IApiVersionParameterSource">API version parameter source</see>.</value>
69-
public IApiVersionParameterSource ParameterSource { get; }
70-
71-
/// <summary>
72-
/// Gets the configured API versioning options.
73-
/// </summary>
74-
/// <value>The configured <see cref="ApiVersioningOptions">API versioning options</see>.</value>
75-
public ApiVersioningOptions Options => options.Value;
34+
// intentionally internal for 6.0, until EndpointBuilder.ServiceProvider is exposed in 7.0
35+
// REF: https://github.com/dotnet/aspnetcore/pull/41238/files#diff-f8807c470bcc3a077fb176668a46df57b4bb99c992b6b7b375665f8bf3903c94R510
36+
internal IServiceProvider? ServiceProvider { get; set; }
7637

7738
/// <summary>
7839
/// Gets the associated builder.
@@ -83,8 +44,9 @@ public ApiVersionSet(
8344
/// <summary>
8445
/// Builds and returns the API version model for the version set.
8546
/// </summary>
47+
/// <param name="options">The configured <see cref="ApiVersioningOptions">API versioning options</see>.</param>
8648
/// <returns>A new <see cref="ApiVersionModel">API version model</see>.</returns>
87-
public virtual ApiVersionModel Build() => Builder.BuildApiVersionModel();
49+
public virtual ApiVersionModel Build( ApiVersioningOptions options ) => Builder.BuildApiVersionModel( options );
8850

8951
/// <summary>
9052
/// Advertises that the specified API version is supported in the version set.

src/AspNetCore/WebApi/src/Asp.Versioning.Http/net6.0/Builder/ApiVersionSetBuilder.cs

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,23 @@
33
namespace Asp.Versioning.Builder;
44

55
using Asp.Versioning.Conventions;
6-
using Microsoft.Extensions.Options;
76

87
/// <summary>
98
/// Represents the builder for an API version set.
109
/// </summary>
1110
public class ApiVersionSetBuilder : ApiVersionConventionBuilderBase, IDeclareApiVersionConventionBuilder
1211
{
1312
private readonly string? name;
14-
private readonly IApiVersionParameterSource parameterSource;
15-
private readonly IOptions<ApiVersioningOptions> options;
1613

1714
/// <summary>
1815
/// Initializes a new instance of the <see cref="ApiVersionSetBuilder"/> class.
1916
/// </summary>
2017
/// <param name="name">The name of the API, if any.</param>
21-
/// <param name="parameterSource">The <see cref="IApiVersionParameterSource">API version
22-
/// parameter source</see>.</param>
23-
/// <param name="options">The configured API versioning options.</param>
24-
public ApiVersionSetBuilder(
25-
string? name,
26-
IApiVersionParameterSource parameterSource,
27-
IOptions<ApiVersioningOptions> options )
28-
{
29-
this.name = name;
30-
this.parameterSource = parameterSource;
31-
this.options = options;
32-
}
18+
public ApiVersionSetBuilder( string? name ) => this.name = name;
19+
20+
// intentionally internal for 6.0, until EndpointBuilder.ServiceProvider is exposed in 7.0
21+
// REF: https://github.com/dotnet/aspnetcore/pull/41238/files#diff-f8807c470bcc3a077fb176668a46df57b4bb99c992b6b7b375665f8bf3903c94R510
22+
internal IServiceProvider? ServiceProvider { get; set; }
3323

3424
/// <summary>
3525
/// Gets or sets a value indicating whether requests report the API version compatibility information in responses.
@@ -41,7 +31,7 @@ public ApiVersionSetBuilder(
4131
/// Builds and returns a new API versioning configuration.
4232
/// </summary>
4333
/// <returns>A new <see cref="ApiVersionSet">API versioning configuration</see>.</returns>
44-
public virtual ApiVersionSet Build() => new( this, name, parameterSource, options );
34+
public virtual ApiVersionSet Build() => new( this, name ) { ServiceProvider = ServiceProvider };
4535

4636
/// <summary>
4737
/// Indicates that all APIs in the version set will report their versions.
@@ -120,17 +110,23 @@ public virtual ApiVersionSetBuilder AdvertisesDeprecatedApiVersion( ApiVersion a
120110
/// <summary>
121111
/// Builds and returns an API version model.
122112
/// </summary>
113+
/// <param name="options">The configured <see cref="ApiVersioningOptions">API versioning options</see>.</param>
123114
/// <returns>A new <see cref="ApiVersionModel">API version model</see>.</returns>
124-
protected internal virtual ApiVersionModel BuildApiVersionModel()
115+
protected internal virtual ApiVersionModel BuildApiVersionModel( ApiVersioningOptions options )
125116
{
117+
if ( options == null )
118+
{
119+
throw new ArgumentNullException( nameof( options ) );
120+
}
121+
126122
if ( VersionNeutral )
127123
{
128124
return ApiVersionModel.Neutral;
129125
}
130126

131127
if ( IsEmpty )
132128
{
133-
return new( options.Value.DefaultApiVersion );
129+
return new( options.DefaultApiVersion );
134130
}
135131

136132
return new(
Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,33 @@
11
// Copyright (c) .NET Foundation and contributors. All rights reserved.
22

3-
#pragma warning disable
4-
53
namespace Asp.Versioning.Builder;
64

7-
using Asp.Versioning.Conventions;
8-
using Asp.Versioning.Routing;
9-
using Microsoft.AspNetCore.Builder;
10-
using Microsoft.AspNetCore.Http;
11-
using Microsoft.AspNetCore.Routing;
12-
using Microsoft.Extensions.Options;
13-
using System.Globalization;
14-
using static Asp.Versioning.ApiVersionParameterLocation;
15-
16-
internal sealed class DefaultApiVersionSetBuilderFactory :
17-
IApiVersionSetBuilderFactory
5+
/// <summary>
6+
/// Represents the default API version set builder factory.
7+
/// </summary>
8+
public class DefaultApiVersionSetBuilderFactory : IApiVersionSetBuilderFactory
189
{
19-
private readonly IApiVersionParameterSource parameterSource;
20-
private readonly IOptions<ApiVersioningOptions> options;
10+
private readonly IServiceProvider serviceProvider;
11+
12+
/// <summary>
13+
/// Initializes a new instance of the <see cref="DefaultApiVersionSetBuilderFactory"/> class.
14+
/// </summary>
15+
/// <param name="serviceProvider">The underlying <see cref="IServiceProvider">service provider</see>.</param>
16+
public DefaultApiVersionSetBuilderFactory( IServiceProvider serviceProvider ) =>
17+
this.serviceProvider = serviceProvider;
2118

22-
public DefaultApiVersionSetBuilderFactory(
23-
IApiVersionParameterSource parameterSource,
24-
IOptions<ApiVersioningOptions> options )
19+
/// <inheritdoc />
20+
public ApiVersionSetBuilder Create( string? name = default )
2521
{
26-
this.parameterSource = parameterSource;
27-
this.options = options;
22+
var instance = CreateInstance( name );
23+
instance.ServiceProvider = serviceProvider;
24+
return instance;
2825
}
2926

30-
public ApiVersionSetBuilder Create( string? name = default ) =>
31-
new( name, parameterSource, options );
32-
}
27+
/// <summary>
28+
/// Creates and returns a new builder instance.
29+
/// </summary>
30+
/// <param name="name">The optional name associated with the builder.</param>
31+
/// <returns>A new <see cref="ApiVersionSetBuilder">API version set builder</see>.</returns>
32+
protected virtual ApiVersionSetBuilder CreateInstance( string? name ) => new( name );
33+
}

src/AspNetCore/WebApi/src/Asp.Versioning.Http/net6.0/Builder/IEndpointConventionBuilderExtensions.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ namespace Microsoft.AspNetCore.Builder;
77
using Asp.Versioning.Routing;
88
using Microsoft.AspNetCore.Http;
99
using Microsoft.AspNetCore.Routing;
10+
using Microsoft.Extensions.DependencyInjection;
11+
using Microsoft.Extensions.Options;
1012
using System.Globalization;
1113
using static Asp.Versioning.ApiVersionParameterLocation;
1214

@@ -72,12 +74,21 @@ private static void Apply(
7274
IVersionedEndpointConventionBuilder conventions,
7375
ApiVersionSet versionSet )
7476
{
77+
// this will change to EndpointBuilder.ServiceProvider in 7.0
78+
// REF: https://github.com/dotnet/aspnetcore/pull/41238/files#diff-f8807c470bcc3a077fb176668a46df57b4bb99c992b6b7b375665f8bf3903c94R510
79+
if ( versionSet.ServiceProvider is not IServiceProvider services )
80+
{
81+
throw new InvalidOperationException( SR.NoEndpointBuilderServices );
82+
}
83+
84+
var parameterSource = services.GetRequiredService<IApiVersionParameterSource>();
85+
var options = services.GetRequiredService<IOptions<ApiVersioningOptions>>().Value;
7586
var requestDelegate = default( RequestDelegate );
76-
var metadata = conventions.Build();
87+
var metadata = conventions.Build( options );
7788

7889
endpointBuilder.Metadata.Add( metadata );
7990

80-
if ( versionSet.Options.ReportApiVersions ||
91+
if ( options.ReportApiVersions ||
8192
versionSet.ReportApiVersions ||
8293
conventions.ReportApiVersions )
8394
{
@@ -86,9 +97,9 @@ private static void Apply(
8697
endpointBuilder.RequestDelegate = requestDelegate;
8798
}
8899

89-
if ( versionSet.ParameterSource.VersionsByMediaType() )
100+
if ( parameterSource.VersionsByMediaType() )
90101
{
91-
var parameterName = versionSet.ParameterSource.GetParameterName( MediaTypeParameter );
102+
var parameterName = parameterSource.GetParameterName( MediaTypeParameter );
92103
requestDelegate = EnsureRequestDelegate( requestDelegate, endpointBuilder.RequestDelegate );
93104
requestDelegate = new ContentTypeApiVersionDecorator( requestDelegate, parameterName );
94105
endpointBuilder.RequestDelegate = requestDelegate;

src/AspNetCore/WebApi/src/Asp.Versioning.Http/net6.0/Builder/IVersionedEndpointConventionBuilder.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public interface IVersionedEndpointConventionBuilder : IEndpointConventionBuilde
2020
/// <summary>
2121
/// Builds and returns a new API version metadata.
2222
/// </summary>
23+
/// <param name="options">The configured <see cref="ApiVersioningOptions">API versioning options</see>.</param>
2324
/// <returns>A new <see cref="ApiVersionMetadata">API version metadata</see>.</returns>
24-
ApiVersionMetadata Build();
25+
ApiVersionMetadata Build( ApiVersioningOptions options );
2526
}

src/AspNetCore/WebApi/src/Asp.Versioning.Http/net6.0/Builder/VersionedEndpointConventionBuilder.cs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,9 @@ public class VersionedEndpointConventionBuilder :
1919
/// <summary>
2020
/// Initializes a new instance of the <see cref="VersionedEndpointConventionBuilder"/> class.
2121
/// </summary>
22-
/// <param name="inner">The inner <see cref="IEndpointConventionBuilder"/> the new
23-
/// instance decorates.</param>
24-
/// <param name="apiVersionSet">The associated <see cref="ApiVersionSet">API version
25-
/// set</see>.</param>
26-
public VersionedEndpointConventionBuilder(
27-
IEndpointConventionBuilder inner,
28-
ApiVersionSet apiVersionSet )
22+
/// <param name="inner">The inner <see cref="IEndpointConventionBuilder"/> the new instance decorates.</param>
23+
/// <param name="apiVersionSet">The associated <see cref="ApiVersionSet">API version set</see>.</param>
24+
public VersionedEndpointConventionBuilder( IEndpointConventionBuilder inner, ApiVersionSet apiVersionSet )
2925
{
3026
this.inner = inner ?? throw new ArgumentNullException( nameof( inner ) );
3127
VersionSet = apiVersionSet ?? throw new ArgumentNullException( nameof( apiVersionSet ) );
@@ -124,13 +120,14 @@ public virtual IVersionedEndpointConventionBuilder AdvertisesDeprecatedApiVersio
124120
/// <summary>
125121
/// Builds and returns a new API version metadata.
126122
/// </summary>
123+
/// <param name="options">The configured <see cref="ApiVersioningOptions">API versioning options</see>.</param>
127124
/// <returns>A new <see cref="ApiVersionMetadata">API version metadata</see>.</returns>
128-
protected virtual ApiVersionMetadata Build()
125+
protected virtual ApiVersionMetadata Build( ApiVersioningOptions options )
129126
{
130127
var name = VersionSet.Name;
131128
ApiVersionModel? apiModel;
132129

133-
if ( VersionNeutral || ( apiModel = VersionSet.Build() ).IsApiVersionNeutral )
130+
if ( VersionNeutral || ( apiModel = VersionSet.Build( options ) ).IsApiVersionNeutral )
134131
{
135132
if ( string.IsNullOrEmpty( name ) )
136133
{
@@ -194,7 +191,7 @@ protected virtual ApiVersionMetadata Build()
194191
name );
195192
}
196193

197-
ApiVersionMetadata IVersionedEndpointConventionBuilder.Build() => Build();
194+
ApiVersionMetadata IVersionedEndpointConventionBuilder.Build( ApiVersioningOptions options ) => Build( options );
198195

199196
void IDeclareApiVersionConventionBuilder.IsApiVersionNeutral() => IsApiVersionNeutral();
200197

src/AspNetCore/WebApi/test/Asp.Versioning.Http.Tests/Builder/ApiVersionSetTest.cs

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@
22

33
namespace Asp.Versioning.Builder;
44

5-
using Microsoft.Extensions.Options;
6-
75
public class ApiVersionSetTest
86
{
97
[Fact]
108
public void report_api_versions_should_derive_from_builder()
119
{
1210
// arrange
13-
var source = Mock.Of<IApiVersionParameterSource>();
14-
var options = Options.Create( new ApiVersioningOptions() );
15-
var builder = new ApiVersionSetBuilder( null, source, options ).ReportApiVersions();
11+
var builder = new ApiVersionSetBuilder( default ).ReportApiVersions();
1612

1713
// act
1814
var versionSet = builder.Build();
@@ -25,14 +21,10 @@ public void report_api_versions_should_derive_from_builder()
2521
public void build_should_construct_model_from_builder()
2622
{
2723
// arrange
28-
var source = Mock.Of<IApiVersionParameterSource>();
29-
var options = Options.Create( new ApiVersioningOptions() );
30-
var versionSet = new ApiVersionSetBuilder( null, source, options )
31-
.IsApiVersionNeutral()
32-
.Build();
24+
var versionSet = new ApiVersionSetBuilder( null ).IsApiVersionNeutral().Build();
3325

3426
// act
35-
var model = versionSet.Build();
27+
var model = versionSet.Build( new() );
3628

3729
// assert
3830
model.Should().BeSameAs( ApiVersionModel.Neutral );
@@ -42,9 +34,7 @@ public void build_should_construct_model_from_builder()
4234
public void advertises_api_version_should_propagate_to_builder()
4335
{
4436
// arrange
45-
var source = Mock.Of<IApiVersionParameterSource>();
46-
var options = Options.Create( new ApiVersioningOptions() );
47-
var builder = new Mock<ApiVersionSetBuilder>( null, source, options ) { CallBase = true };
37+
var builder = new Mock<ApiVersionSetBuilder>( null ) { CallBase = true };
4838

4939
builder.Setup( b => b.AdvertisesApiVersion( It.IsAny<ApiVersion>() ) );
5040

@@ -62,9 +52,7 @@ public void advertises_api_version_should_propagate_to_builder()
6252
public void advertises_deprecated_api_version_should_propagate_to_builder()
6353
{
6454
// arrange
65-
var source = Mock.Of<IApiVersionParameterSource>();
66-
var options = Options.Create( new ApiVersioningOptions() );
67-
var builder = new Mock<ApiVersionSetBuilder>( null, source, options ) { CallBase = true };
55+
var builder = new Mock<ApiVersionSetBuilder>( null ) { CallBase = true };
6856

6957
builder.Setup( b => b.AdvertisesDeprecatedApiVersion( It.IsAny<ApiVersion>() ) );
7058

0 commit comments

Comments
 (0)