diff --git a/src/Mvc/src/Microsoft.AspNetCore.Mvc.Api.Analyzers/SymbolApiResponseMetadataProvider.cs b/src/Mvc/src/Microsoft.AspNetCore.Mvc.Api.Analyzers/SymbolApiResponseMetadataProvider.cs index 2be586958d..9b6a1b759c 100644 --- a/src/Mvc/src/Microsoft.AspNetCore.Mvc.Api.Analyzers/SymbolApiResponseMetadataProvider.cs +++ b/src/Mvc/src/Microsoft.AspNetCore.Mvc.Api.Analyzers/SymbolApiResponseMetadataProvider.cs @@ -160,7 +160,7 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers internal static IReadOnlyList GetConventionTypes(in ApiControllerSymbolCache symbolCache, IMethodSymbol method) { - var attributes = method.ContainingType.GetAttributes(symbolCache.ApiConventionTypeAttribute).ToArray(); + var attributes = method.ContainingType.GetAttributes(symbolCache.ApiConventionTypeAttribute, inherit: true).ToArray(); if (attributes.Length == 0) { attributes = method.ContainingAssembly.GetAttributes(symbolCache.ApiConventionTypeAttribute).ToArray(); diff --git a/src/Mvc/test/Mvc.Api.Analyzers.Test/SymbolApiResponseMetadataProviderTest.cs b/src/Mvc/test/Mvc.Api.Analyzers.Test/SymbolApiResponseMetadataProviderTest.cs index 57d823e8c6..d93a2ee158 100644 --- a/src/Mvc/test/Mvc.Api.Analyzers.Test/SymbolApiResponseMetadataProviderTest.cs +++ b/src/Mvc/test/Mvc.Api.Analyzers.Test/SymbolApiResponseMetadataProviderTest.cs @@ -290,6 +290,50 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers }); } + [Fact] + public async Task GetDeclaredResponseMetadata_ApiConventionTypeAttributeOnType_Works() + { + // Arrange + var type = typeof(GetDeclaredResponseMetadata_ApiConventionTypeAttributeOnType); + var compilation = await GetResponseMetadataCompilation(); + var controller = compilation.GetTypeByMetadataName(type.FullName); + var method = (IMethodSymbol)controller.GetMembers().First(); + var symbolCache = new ApiControllerSymbolCache(compilation); + + // Act + var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method); + + // Assert + // We should expect 3 entries specified by DefaultApiConventions.Post + Assert.Collection( + result.OrderBy(r => r.StatusCode), + metadata => Assert.True(metadata.IsDefault), + metadata => Assert.Equal(201, metadata.StatusCode), + metadata => Assert.Equal(400, metadata.StatusCode)); + } + + [Fact] + public async Task GetDeclaredResponseMetadata_ApiConventionTypeAttributeOnBaseType_Works() + { + // Arrange + var type = typeof(GetDeclaredResponseMetadata_ApiConventionTypeAttributeOnBaseType); + var compilation = await GetResponseMetadataCompilation(); + var controller = compilation.GetTypeByMetadataName(type.FullName); + var method = (IMethodSymbol)controller.GetMembers().First(); + var symbolCache = new ApiControllerSymbolCache(compilation); + + // Act + var result = SymbolApiResponseMetadataProvider.GetDeclaredResponseMetadata(symbolCache, method); + + // Assert + // We should expect 3 entries specified by DefaultApiConventions.Post + Assert.Collection( + result.OrderBy(r => r.StatusCode), + metadata => Assert.True(metadata.IsDefault), + metadata => Assert.Equal(201, metadata.StatusCode), + metadata => Assert.Equal(400, metadata.StatusCode)); + } + [Fact] public Task GetStatusCode_ReturnsValueFromConstructor() { diff --git a/src/Mvc/test/Mvc.Api.Analyzers.Test/TestFiles/SymbolApiResponseMetadataProviderTest/GetResponseMetadataTests.cs b/src/Mvc/test/Mvc.Api.Analyzers.Test/TestFiles/SymbolApiResponseMetadataProviderTest/GetResponseMetadataTests.cs index 389617609b..d0728bbef3 100644 --- a/src/Mvc/test/Mvc.Api.Analyzers.Test/TestFiles/SymbolApiResponseMetadataProviderTest/GetResponseMetadataTests.cs +++ b/src/Mvc/test/Mvc.Api.Analyzers.Test/TestFiles/SymbolApiResponseMetadataProviderTest/GetResponseMetadataTests.cs @@ -90,4 +90,20 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers } } } + + [ApiConventionType(typeof(DefaultApiConventions))] + public class GetDeclaredResponseMetadata_ApiConventionTypeAttributeOnType : Controller + { + public IActionResult Post(object model) => null; + } + + [ApiConventionType(typeof(DefaultApiConventions))] + public class GetDeclaredResponseMetadata_ApiConventionTypeAttributeOnBaseTypeBase + { + } + + public class GetDeclaredResponseMetadata_ApiConventionTypeAttributeOnBaseType : GetDeclaredResponseMetadata_ApiConventionTypeAttributeOnBaseTypeBase + { + public IActionResult Post(object model) => null; + } }