Skip to content

Commit 1363443

Browse files
committed
Log registered IApiDescriptionProvider implementations on load
1 parent 19a66f1 commit 1363443

File tree

3 files changed

+48
-2
lines changed

3 files changed

+48
-2
lines changed

src/Mvc/Mvc.ApiExplorer/src/ApiDescriptionGroupCollectionProvider.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33

44
using System.Linq;
55
using Microsoft.AspNetCore.Mvc.Infrastructure;
6+
using Microsoft.Extensions.Logging;
67

78
namespace Microsoft.AspNetCore.Mvc.ApiExplorer;
89

910
/// <inheritdoc />
10-
public class ApiDescriptionGroupCollectionProvider : IApiDescriptionGroupCollectionProvider
11+
public partial class ApiDescriptionGroupCollectionProvider : IApiDescriptionGroupCollectionProvider
1112
{
1213
private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;
1314
private readonly IApiDescriptionProvider[] _apiDescriptionProviders;
1415

1516
private ApiDescriptionGroupCollection? _apiDescriptionGroups;
17+
private readonly ILogger? _logger;
1618

1719
/// <summary>
1820
/// Creates a new instance of <see cref="ApiDescriptionGroupCollectionProvider"/>.
@@ -28,7 +30,27 @@ public ApiDescriptionGroupCollectionProvider(
2830
IEnumerable<IApiDescriptionProvider> apiDescriptionProviders)
2931
{
3032
_actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
31-
_apiDescriptionProviders = apiDescriptionProviders.OrderBy(item => item.Order).ToArray();
33+
_apiDescriptionProviders = [.. apiDescriptionProviders.OrderBy(item => item.Order)];
34+
}
35+
36+
/// <summary>
37+
/// Creates a new instance of <see cref="ApiDescriptionGroupCollectionProvider"/>.
38+
/// </summary>
39+
/// <param name="actionDescriptorCollectionProvider">
40+
/// The <see cref="IActionDescriptorCollectionProvider"/>.
41+
/// </param>
42+
/// <param name="apiDescriptionProviders">
43+
/// The <see cref="IEnumerable{IApiDescriptionProvider}"/>.
44+
/// </param>
45+
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to construct a logger.</param>
46+
public ApiDescriptionGroupCollectionProvider(
47+
IActionDescriptorCollectionProvider actionDescriptorCollectionProvider,
48+
IEnumerable<IApiDescriptionProvider> apiDescriptionProviders,
49+
ILoggerFactory loggerFactory)
50+
{
51+
_actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
52+
_apiDescriptionProviders = [.. apiDescriptionProviders.OrderBy(item => item.Order)];
53+
_logger = loggerFactory.CreateLogger<ApiDescriptionGroupCollectionProvider>();
3254
}
3355

3456
/// <inheritdoc />
@@ -52,6 +74,10 @@ private ApiDescriptionGroupCollection GetCollection(ActionDescriptorCollection a
5274

5375
foreach (var provider in _apiDescriptionProviders)
5476
{
77+
if (_logger is not null)
78+
{
79+
Log.ApiDescriptionProviderExecuting(_logger, provider.GetType().Name, provider.GetType().Assembly.GetName().Name);
80+
}
5581
provider.OnProvidersExecuting(context);
5682
}
5783

@@ -67,4 +93,10 @@ private ApiDescriptionGroupCollection GetCollection(ActionDescriptorCollection a
6793

6894
return new ApiDescriptionGroupCollection(groups, actionDescriptors.Version);
6995
}
96+
97+
private static partial class Log
98+
{
99+
[LoggerMessage(2, LogLevel.Debug, "Executing API description provider '{ProviderName}' from assembly {ProviderAssembly}.", EventName = "ApiDescriptionProviderExecuting")]
100+
public static partial void ApiDescriptionProviderExecuting(ILogger logger, string providerName, string? providerAssembly);
101+
}
70102
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
#nullable enable
2+
Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescriptionGroupCollectionProvider.ApiDescriptionGroupCollectionProvider(Microsoft.AspNetCore.Mvc.Infrastructure.IActionDescriptorCollectionProvider! actionDescriptorCollectionProvider, System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionProvider!>! apiDescriptionProviders, Microsoft.Extensions.Logging.ILoggerFactory! loggerFactory) -> void

src/Mvc/test/Mvc.FunctionalTests/ApiExplorerTest.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,19 @@ public async Task ApiAction_ForActionWithVoidResponseType(string path, Type type
15521552
});
15531553
}
15541554

1555+
[Fact]
1556+
public async Task ApiExplorer_LogsInvokedDescriptionProvidersOnStartup()
1557+
{
1558+
// Arrange & Act
1559+
var response = await Client.GetAsync("http://localhost/ApiExplorerHttpMethod/All");
1560+
1561+
// Assert
1562+
Assert.Contains(TestSink.Writes, w => w.EventId.Name?.Equals("ApiDescriptionProviderExecuting", StringComparison.Ordinal) == true);
1563+
Assert.Contains(TestSink.Writes, w => w.LoggerName.Equals("Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescriptionGroupCollectionProvider", StringComparison.Ordinal));
1564+
Assert.Contains(TestSink.Writes, w => w.Message.Equals("Executing API description provider 'DefaultApiDescriptionProvider' from assembly Microsoft.AspNetCore.Mvc.ApiExplorer.", StringComparison.Ordinal));
1565+
Assert.Contains(TestSink.Writes, w => w.Message.Equals("Executing API description provider 'JsonPatchOperationsArrayProvider' from assembly Microsoft.AspNetCore.Mvc.NewtonsoftJson.", StringComparison.Ordinal));
1566+
}
1567+
15551568
private IEnumerable<string> GetSortedMediaTypes(ApiExplorerResponseType apiResponseType)
15561569
{
15571570
return apiResponseType.ResponseFormats

0 commit comments

Comments
 (0)