Skip to content

Commit 665afc0

Browse files
Add support for custom group name formatting
1 parent 32448ab commit 665afc0

7 files changed

+578
-18
lines changed

src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/ApiExplorerOptions.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,13 @@ public IApiVersionParameterSource ApiVersionParameterSource
4646
/// </summary>
4747
/// <value>The name associated with the <see cref="ApiVersionRouteConstraint">API version route constraint</see>.</value>
4848
public string RouteConstraintName { get; set; } = string.Empty;
49+
50+
/// <summary>
51+
/// Gets or sets the function used to format the combination of a group name and API version.
52+
/// </summary>
53+
/// <value>The <see cref="FormatGroupNameCallback">callback</see> used to format the combination of
54+
/// a group name and API version. The default value is <c>null</c>.</value>
55+
/// <remarks>The specified callback will only be invoked if a group name has been configured. The API
56+
/// version will be provided formatted according to the <see cref="GroupNameFormat">group name format</see>.</remarks>
57+
public FormatGroupNameCallback? FormatGroupName { get; set; }
4958
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
namespace Microsoft.AspNetCore.Builder;
4+
5+
using Asp.Versioning;
6+
using Asp.Versioning.ApiExplorer;
7+
using Microsoft.AspNetCore.Mvc.Infrastructure;
8+
using Microsoft.AspNetCore.Routing;
9+
using Microsoft.Extensions.DependencyInjection;
10+
using Microsoft.Extensions.Options;
11+
12+
internal sealed class ApiVersionDescriptionProviderFactory : IApiVersionDescriptionProviderFactory
13+
{
14+
private readonly IServiceProvider serviceProvider;
15+
private readonly Func<EndpointDataSource, IActionDescriptorCollectionProvider, ISunsetPolicyManager, IOptions<ApiExplorerOptions>, IApiVersionDescriptionProvider> activator;
16+
17+
public ApiVersionDescriptionProviderFactory(
18+
IServiceProvider serviceProvider,
19+
Func<EndpointDataSource, IActionDescriptorCollectionProvider, ISunsetPolicyManager, IOptions<ApiExplorerOptions>, IApiVersionDescriptionProvider> activator )
20+
{
21+
this.serviceProvider = serviceProvider;
22+
this.activator = activator;
23+
}
24+
25+
public IApiVersionDescriptionProvider Create( EndpointDataSource endpointDataSource )
26+
{
27+
var actionDescriptorCollectionProvider = serviceProvider.GetRequiredService<IActionDescriptorCollectionProvider>();
28+
var sunsetPolicyManager = serviceProvider.GetRequiredService<ISunsetPolicyManager>();
29+
var options = serviceProvider.GetRequiredService<IOptions<ApiExplorerOptions>>();
30+
return activator( endpointDataSource, actionDescriptorCollectionProvider, sunsetPolicyManager, options );
31+
}
32+
}

src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/DependencyInjection/IApiVersioningBuilderExtensions.cs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ namespace Microsoft.Extensions.DependencyInjection;
44

55
using Asp.Versioning;
66
using Asp.Versioning.ApiExplorer;
7+
using Microsoft.AspNetCore.Builder;
78
using Microsoft.AspNetCore.Mvc.ApiExplorer;
9+
using Microsoft.AspNetCore.Mvc.Infrastructure;
810
using Microsoft.AspNetCore.Mvc.ModelBinding;
911
using Microsoft.AspNetCore.Routing;
1012
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -61,7 +63,8 @@ private static void AddApiExplorerServices( IServiceCollection services )
6163

6264
services.AddMvcCore().AddApiExplorer();
6365
services.TryAddSingleton<IOptionsFactory<ApiExplorerOptions>, ApiExplorerOptionsFactory<ApiExplorerOptions>>();
64-
services.TryAddSingleton<IApiVersionDescriptionProvider, DefaultApiVersionDescriptionProvider>();
66+
services.TryAddTransient( ResolveApiVersionDescriptionProviderFactory );
67+
services.TryAddSingleton( ResolveApiVersionDescriptionProvider );
6568

6669
// use internal constructor until ASP.NET Core fixes their bug
6770
// BUG: https://github.com/dotnet/aspnetcore/issues/41773
@@ -73,4 +76,50 @@ private static void AddApiExplorerServices( IServiceCollection services )
7376
sp.GetRequiredService<IInlineConstraintResolver>(),
7477
sp.GetRequiredService<IOptions<ApiExplorerOptions>>() ) ) );
7578
}
79+
80+
private static IApiVersionDescriptionProviderFactory ResolveApiVersionDescriptionProviderFactory( IServiceProvider serviceProvider )
81+
{
82+
var options = serviceProvider.GetRequiredService<IOptions<ApiExplorerOptions>>();
83+
var mightUseCustomGroups = options.Value.FormatGroupName is not null;
84+
85+
return new ApiVersionDescriptionProviderFactory( serviceProvider, mightUseCustomGroups ? NewGroupedProvider : NewDefaultProvider );
86+
87+
static IApiVersionDescriptionProvider NewDefaultProvider(
88+
EndpointDataSource endpointDataSource,
89+
IActionDescriptorCollectionProvider actionDescriptorCollectionProvider,
90+
ISunsetPolicyManager sunsetPolicyManager,
91+
IOptions<ApiExplorerOptions> apiExplorerOptions ) =>
92+
new DefaultApiVersionDescriptionProvider( endpointDataSource, actionDescriptorCollectionProvider, sunsetPolicyManager, apiExplorerOptions );
93+
94+
static IApiVersionDescriptionProvider NewGroupedProvider(
95+
EndpointDataSource endpointDataSource,
96+
IActionDescriptorCollectionProvider actionDescriptorCollectionProvider,
97+
ISunsetPolicyManager sunsetPolicyManager,
98+
IOptions<ApiExplorerOptions> apiExplorerOptions ) =>
99+
new GroupedApiVersionDescriptionProvider( endpointDataSource, actionDescriptorCollectionProvider, sunsetPolicyManager, apiExplorerOptions );
100+
}
101+
102+
private static IApiVersionDescriptionProvider ResolveApiVersionDescriptionProvider( IServiceProvider serviceProvider )
103+
{
104+
var endpointDataSource = serviceProvider.GetRequiredService<EndpointDataSource>();
105+
var actionDescriptorCollectionProvider = serviceProvider.GetRequiredService<IActionDescriptorCollectionProvider>();
106+
var sunsetPolicyManager = serviceProvider.GetRequiredService<ISunsetPolicyManager>();
107+
var options = serviceProvider.GetRequiredService<IOptions<ApiExplorerOptions>>();
108+
var mightUseCustomGroups = options.Value.FormatGroupName is not null;
109+
110+
if ( mightUseCustomGroups )
111+
{
112+
return new GroupedApiVersionDescriptionProvider(
113+
endpointDataSource,
114+
actionDescriptorCollectionProvider,
115+
sunsetPolicyManager,
116+
options );
117+
}
118+
119+
return new DefaultApiVersionDescriptionProvider(
120+
endpointDataSource,
121+
actionDescriptorCollectionProvider,
122+
sunsetPolicyManager,
123+
options );
124+
}
76125
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
namespace Asp.Versioning.ApiExplorer;
4+
5+
/// <summary>
6+
/// Represents a callback function used to format a group name.
7+
/// </summary>
8+
/// <param name="groupName">The associated group name.</param>
9+
/// <param name="apiVersion">A formatted API version.</param>
10+
/// <returns>The format result.</returns>
11+
public delegate string FormatGroupNameCallback( string groupName, string apiVersion );

0 commit comments

Comments
 (0)