Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9d18108

Browse filesBrowse files
Added IEndpointInspector so that controller action endpoints are not processed by min api endpoint collators. Related #1066
1 parent 1c13628 commit 9d18108
Copy full SHA for 9d18108

File tree

Expand file treeCollapse file tree

8 files changed

+112
-22
lines changed
Filter options
Expand file treeCollapse file tree

8 files changed

+112
-22
lines changed
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
namespace Asp.Versioning.ApiExplorer;
4+
5+
using Microsoft.AspNetCore.Http;
6+
7+
/// <summary>
8+
/// Represents the default <see cref="IEndpointInspector">endpoint inspector</see>.
9+
/// </summary>
10+
[CLSCompliant(false)]
11+
public sealed class DefaultEndpointInspector : IEndpointInspector
12+
{
13+
/// <inheritdoc />
14+
public bool IsControllerAction( Endpoint endpoint ) => false;
15+
}

‎src/AspNetCore/WebApi/src/Asp.Versioning.Http/ApiExplorer/EndpointApiVersionMetadataCollationProvider.cs

Copy file name to clipboardExpand all lines: src/AspNetCore/WebApi/src/Asp.Versioning.Http/ApiExplorer/EndpointApiVersionMetadataCollationProvider.cs
+17-2Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,29 @@ namespace Asp.Versioning.ApiExplorer;
1212
public sealed class EndpointApiVersionMetadataCollationProvider : IApiVersionMetadataCollationProvider
1313
{
1414
private readonly EndpointDataSource endpointDataSource;
15+
private readonly IEndpointInspector endpointInspector;
1516
private int version;
1617

1718
/// <summary>
1819
/// Initializes a new instance of the <see cref="EndpointApiVersionMetadataCollationProvider"/> class.
1920
/// </summary>
2021
/// <param name="endpointDataSource">The underlying <see cref="endpointDataSource">endpoint data source</see>.</param>
22+
[Obsolete( "Use the constructor that accepts IEndpointInspector. This constructor will be removed in a future version." )]
2123
public EndpointApiVersionMetadataCollationProvider( EndpointDataSource endpointDataSource )
24+
: this( endpointDataSource, new DefaultEndpointInspector() ) { }
25+
26+
/// <summary>
27+
/// Initializes a new instance of the <see cref="EndpointApiVersionMetadataCollationProvider"/> class.
28+
/// </summary>
29+
/// <param name="endpointDataSource">The underlying <see cref="endpointDataSource">endpoint data source</see>.</param>
30+
/// <param name="endpointInspector">The <see cref="IEndpointInspector">endpoint inspector</see> used to inspect endpoints.</param>
31+
public EndpointApiVersionMetadataCollationProvider( EndpointDataSource endpointDataSource, IEndpointInspector endpointInspector )
2232
{
23-
this.endpointDataSource = endpointDataSource ?? throw new ArgumentNullException( nameof( endpointDataSource ) );
33+
ArgumentNullException.ThrowIfNull( endpointDataSource );
34+
ArgumentNullException.ThrowIfNull( endpointInspector );
35+
36+
this.endpointDataSource = endpointDataSource;
37+
this.endpointInspector = endpointInspector;
2438
ChangeToken.OnChange( endpointDataSource.GetChangeToken, () => ++version );
2539
}
2640

@@ -38,7 +52,8 @@ public void Execute( ApiVersionMetadataCollationContext context )
3852
{
3953
var endpoint = endpoints[i];
4054

41-
if ( endpoint.Metadata.GetMetadata<ApiVersionMetadata>() is not ApiVersionMetadata item )
55+
if ( endpoint.Metadata.GetMetadata<ApiVersionMetadata>() is not ApiVersionMetadata item ||
56+
endpointInspector.IsControllerAction( endpoint ) )
4257
{
4358
continue;
4459
}
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
namespace Asp.Versioning.ApiExplorer;
4+
5+
using Microsoft.AspNetCore.Http;
6+
7+
/// <summary>
8+
/// Defines the behavior of an endpoint inspector.
9+
/// </summary>
10+
[CLSCompliant( false )]
11+
public interface IEndpointInspector
12+
{
13+
/// <summary>
14+
/// Determines whether the specified endpoint is a controller action.
15+
/// </summary>
16+
/// <param name="endpoint">The <see cref="Endpoint">endpoint</see> to inspect.</param>
17+
/// <returns>True if the <paramref name="endpoint"/> is for a controller action; otherwise, false.</returns>
18+
bool IsControllerAction( Endpoint endpoint );
19+
}

‎src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs

Copy file name to clipboardExpand all lines: src/AspNetCore/WebApi/src/Asp.Versioning.Http/DependencyInjection/IServiceCollectionExtensions.cs
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ private static void AddApiVersioningServices( IServiceCollection services )
8989
services.TryAddEnumerable( Transient<IPostConfigureOptions<RouteOptions>, ApiVersioningRouteOptionsSetup>() );
9090
services.TryAddEnumerable( Singleton<MatcherPolicy, ApiVersionMatcherPolicy>() );
9191
services.TryAddEnumerable( Singleton<IApiVersionMetadataCollationProvider, EndpointApiVersionMetadataCollationProvider>() );
92+
services.TryAddTransient<IEndpointInspector, DefaultEndpointInspector>();
9293
services.Replace( WithLinkGeneratorDecorator( services ) );
9394
TryAddProblemDetailsRfc7231Compliance( services );
9495
TryAddErrorObjectJsonOptions( services );

‎src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/ApiVersionDescriptionProviderFactory.cs

Copy file name to clipboardExpand all lines: src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/ApiVersionDescriptionProviderFactory.cs
+4-1Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,29 @@ internal sealed class ApiVersionDescriptionProviderFactory : IApiVersionDescript
1616
{
1717
private readonly ISunsetPolicyManager sunsetPolicyManager;
1818
private readonly IApiVersionMetadataCollationProvider[] providers;
19+
private readonly IEndpointInspector endpointInspector;
1920
private readonly IOptions<ApiExplorerOptions> options;
2021
private readonly Activator activator;
2122

2223
public ApiVersionDescriptionProviderFactory(
2324
Activator activator,
2425
ISunsetPolicyManager sunsetPolicyManager,
2526
IEnumerable<IApiVersionMetadataCollationProvider> providers,
27+
IEndpointInspector endpointInspector,
2628
IOptions<ApiExplorerOptions> options )
2729
{
2830
this.activator = activator;
2931
this.sunsetPolicyManager = sunsetPolicyManager;
3032
this.providers = providers.ToArray();
33+
this.endpointInspector = endpointInspector;
3134
this.options = options;
3235
}
3336

3437
public IApiVersionDescriptionProvider Create( EndpointDataSource endpointDataSource )
3538
{
3639
var collators = new List<IApiVersionMetadataCollationProvider>( capacity: providers.Length + 1 )
3740
{
38-
new EndpointApiVersionMetadataCollationProvider( endpointDataSource ),
41+
new EndpointApiVersionMetadataCollationProvider( endpointDataSource, endpointInspector ),
3942
};
4043

4144
collators.AddRange( providers );

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

Copy file name to clipboardExpand all lines: src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/DependencyInjection/IApiVersioningBuilderExtensions.cs
+17-19Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ namespace Microsoft.Extensions.DependencyInjection;
55
using Asp.Versioning;
66
using Asp.Versioning.ApiExplorer;
77
using Microsoft.AspNetCore.Builder;
8+
using Microsoft.AspNetCore.Http;
89
using Microsoft.AspNetCore.Mvc.ApiExplorer;
910
using Microsoft.AspNetCore.Mvc.ModelBinding;
1011
using Microsoft.AspNetCore.Routing;
1112
using Microsoft.Extensions.DependencyInjection.Extensions;
1213
using Microsoft.Extensions.Options;
14+
using Microsoft.Extensions.Primitives;
1315
using static ServiceDescriptor;
1416

1517
/// <summary>
@@ -70,40 +72,36 @@ private static IApiVersionDescriptionProviderFactory ResolveApiVersionDescriptio
7072
{
7173
var sunsetPolicyManager = serviceProvider.GetRequiredService<ISunsetPolicyManager>();
7274
var providers = serviceProvider.GetServices<IApiVersionMetadataCollationProvider>();
75+
var inspector = serviceProvider.GetRequiredService<IEndpointInspector>();
7376
var options = serviceProvider.GetRequiredService<IOptions<ApiExplorerOptions>>();
74-
var mightUseCustomGroups = options.Value.FormatGroupName is not null;
7577

7678
return new ApiVersionDescriptionProviderFactory(
77-
mightUseCustomGroups ? NewGroupedProvider : NewDefaultProvider,
79+
NewDefaultProvider,
7880
sunsetPolicyManager,
7981
providers,
82+
inspector,
8083
options );
8184

82-
static IApiVersionDescriptionProvider NewDefaultProvider(
85+
static DefaultApiVersionDescriptionProvider NewDefaultProvider(
8386
IEnumerable<IApiVersionMetadataCollationProvider> providers,
8487
ISunsetPolicyManager sunsetPolicyManager,
8588
IOptions<ApiExplorerOptions> apiExplorerOptions ) =>
86-
new DefaultApiVersionDescriptionProvider( providers, sunsetPolicyManager, apiExplorerOptions );
87-
88-
static IApiVersionDescriptionProvider NewGroupedProvider(
89-
IEnumerable<IApiVersionMetadataCollationProvider> providers,
90-
ISunsetPolicyManager sunsetPolicyManager,
91-
IOptions<ApiExplorerOptions> apiExplorerOptions ) =>
92-
new GroupedApiVersionDescriptionProvider( providers, sunsetPolicyManager, apiExplorerOptions );
89+
new( providers, sunsetPolicyManager, apiExplorerOptions );
9390
}
9491

9592
private static IApiVersionDescriptionProvider ResolveApiVersionDescriptionProvider( IServiceProvider serviceProvider )
9693
{
97-
var providers = serviceProvider.GetServices<IApiVersionMetadataCollationProvider>();
98-
var sunsetPolicyManager = serviceProvider.GetRequiredService<ISunsetPolicyManager>();
99-
var options = serviceProvider.GetRequiredService<IOptions<ApiExplorerOptions>>();
100-
var mightUseCustomGroups = options.Value.FormatGroupName is not null;
94+
var factory = serviceProvider.GetRequiredService<IApiVersionDescriptionProviderFactory>();
95+
var endpointDataSource = new EmptyEndpointDataSource();
96+
return factory.Create( endpointDataSource );
97+
}
98+
99+
private sealed class EmptyEndpointDataSource : EndpointDataSource
100+
{
101+
public override IReadOnlyList<Endpoint> Endpoints => Array.Empty<Endpoint>();
101102

102-
if ( mightUseCustomGroups )
103-
{
104-
return new GroupedApiVersionDescriptionProvider( providers, sunsetPolicyManager, options );
105-
}
103+
public override IChangeToken GetChangeToken() => new CancellationChangeToken( CancellationToken.None );
106104

107-
return new DefaultApiVersionDescriptionProvider( providers, sunsetPolicyManager, options );
105+
public override IReadOnlyList<Endpoint> GetGroupedEndpoints( RouteGroupContext context ) => Array.Empty<Endpoint>();
108106
}
109107
}
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
namespace Asp.Versioning.ApiExplorer;
4+
5+
using Microsoft.AspNetCore.Http;
6+
using Microsoft.AspNetCore.Mvc;
7+
8+
/// <summary>
9+
/// Represents the <see cref="IEndpointInspector">inspector</see> that understands
10+
/// <see cref="Endpoint">endpoints</see> defined by MVC controllers.
11+
/// </summary>
12+
[CLSCompliant(false)]
13+
public sealed class MvcEndpointInspector : IEndpointInspector
14+
{
15+
/// <inheritdoc />
16+
public bool IsControllerAction( Endpoint endpoint )
17+
{
18+
ArgumentNullException.ThrowIfNull( endpoint );
19+
return endpoint.Metadata.Any( static attribute => attribute is ControllerAttribute );
20+
}
21+
}

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

Copy file name to clipboardExpand all lines: src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/DependencyInjection/IApiVersioningBuilderExtensions.cs
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ private static void AddServices( IServiceCollection services )
6767
services.TryAddEnumerable( Transient<IApiControllerSpecification, ApiBehaviorSpecification>() );
6868
services.TryAddEnumerable( Singleton<IApiVersionMetadataCollationProvider, ActionApiVersionMetadataCollationProvider>() );
6969
services.Replace( WithUrlHelperFactoryDecorator( services ) );
70+
services.TryReplace<IEndpointInspector, DefaultEndpointInspector, MvcEndpointInspector>();
7071
}
7172

7273
private static object CreateInstance( this IServiceProvider services, ServiceDescriptor descriptor )
@@ -84,6 +85,23 @@ private static object CreateInstance( this IServiceProvider services, ServiceDes
8485
return ActivatorUtilities.GetServiceOrCreateInstance( services, descriptor.ImplementationType! );
8586
}
8687

88+
private static void TryReplace<TService, TImplementation, TReplacement>( this IServiceCollection services )
89+
{
90+
var serviceType = typeof( TService );
91+
var implementationType = typeof( TImplementation );
92+
93+
for ( var i = services.Count - 1; i >= 0; i-- )
94+
{
95+
var service = services[i];
96+
97+
if ( service.ServiceType == serviceType && service.ImplementationType == implementationType )
98+
{
99+
services[i] = Describe( serviceType, typeof( TReplacement ), service.Lifetime );
100+
break;
101+
}
102+
}
103+
}
104+
87105
[SkipLocalsInit]
88106
private static DecoratedServiceDescriptor WithUrlHelperFactoryDecorator( IServiceCollection services )
89107
{

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.