Skip to content

Commit a7491e5

Browse files
committed
Use non-compiler-generated declaring types for "controller" name
1 parent 0109916 commit a7491e5

File tree

2 files changed

+49
-5
lines changed

2 files changed

+49
-5
lines changed

src/Mvc/Mvc.ApiExplorer/src/EndpointMetadataApiDescriptionProvider.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Diagnostics;
77
using System.Linq;
88
using System.Reflection;
9+
using System.Runtime.CompilerServices;
910
using System.Threading;
1011
using Microsoft.AspNetCore.Http;
1112
using Microsoft.AspNetCore.Http.Metadata;
@@ -21,7 +22,6 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
2122
{
2223
internal class EndpointMetadataApiDescriptionProvider : IApiDescriptionProvider
2324
{
24-
// IApiResponseMetadataProvider,
2525
private readonly EndpointDataSource _endpointDataSource;
2626

2727
// Executes before MVC's DefaultApiDescriptionProvider and GrpcHttpApiDescriptionProvider for no particular reason :D
@@ -57,6 +57,21 @@ public void OnProvidersExecuted(ApiDescriptionProviderContext context)
5757

5858
private static ApiDescription CreateApiDescription(RouteEndpoint routeEndpoint, string httpMethod, MethodInfo methodInfo)
5959
{
60+
// Swagger uses the "controller" name to group endpoints together.
61+
// For now, put all methods defined the same declaring type together.
62+
string controllerName;
63+
64+
if (methodInfo.DeclaringType is not null && !IsCompilerGenerated(methodInfo.DeclaringType))
65+
{
66+
controllerName = methodInfo.DeclaringType.Name;
67+
}
68+
else
69+
{
70+
// If the declaring type is null or compiler-generated (e.g. lambdas),
71+
// group the methods under a "Map" controller.
72+
controllerName = "Map";
73+
}
74+
6075
var apiDescription = new ApiDescription
6176
{
6277
HttpMethod = httpMethod,
@@ -65,10 +80,7 @@ private static ApiDescription CreateApiDescription(RouteEndpoint routeEndpoint,
6580
{
6681
RouteValues =
6782
{
68-
// Swagger uses this to group endpoints together.
69-
// For now, put all endpoints configured with Map(Delegate) together.
70-
// TODO: Use some other metadata for this.
71-
["controller"] = "Map",
83+
["controller"] = controllerName,
7284
},
7385
},
7486
};
@@ -288,5 +300,11 @@ private static void AddResponseContentTypes(IList<ApiResponseFormat> apiResponse
288300
});
289301
}
290302
}
303+
304+
// The CompilerGeneratedAttribute doesn't always get added so we also check if the type name starts with "<"
305+
// For example,w "<>c" is a "declaring" type the C# compiler will generate without the attribute for a top-level lambda
306+
// REVIEW: Is there a better way to do this?
307+
private static bool IsCompilerGenerated(Type type) =>
308+
Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute)) || type.Name.StartsWith('<');
291309
}
292310
}

src/Mvc/Mvc.ApiExplorer/test/EndpointMetadataApiDescriptionProviderTest.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,28 @@ public void ApiDescription_NotCreatedIfNoHttpMethods()
3737
Assert.Empty(apiDescriptions);
3838
}
3939

40+
41+
[Fact]
42+
public void ApiDescription_UsesDeclaringTypeAsControllerName()
43+
{
44+
var apiDescriptions = GetApiDescriptions(((Action)TestAction).Method);
45+
46+
var apiDescription = Assert.Single(apiDescriptions);
47+
var declaringTypeName = typeof(EndpointMetadataApiDescriptionProviderTest).Name;
48+
Assert.Equal(declaringTypeName, apiDescription.ActionDescriptor.RouteValues["controller"]);
49+
}
50+
51+
[Fact]
52+
public void ApiDescription_UsesMapAsControllerNameIfNoDeclaringType()
53+
{
54+
Action action = () => { };
55+
56+
var apiDescriptions = GetApiDescriptions(action.Method);
57+
58+
var apiDescription = Assert.Single(apiDescriptions);
59+
Assert.Equal("Map", apiDescription.ActionDescriptor.RouteValues["controller"]);
60+
}
61+
4062
private IList<ApiDescription> GetApiDescriptions(
4163
MethodInfo methodInfo,
4264
IEnumerable<string> httpMethods = null,
@@ -58,5 +80,9 @@ private IList<ApiDescription> GetApiDescriptions(
5880

5981
return context.Results;
6082
}
83+
84+
private static void TestAction()
85+
{
86+
}
6187
}
6288
}

0 commit comments

Comments
 (0)