diff --git a/src/Mvc/Mvc.ApiExplorer/src/EndpointMetadataApiDescriptionProvider.cs b/src/Mvc/Mvc.ApiExplorer/src/EndpointMetadataApiDescriptionProvider.cs index 2f25045d3787..cdd33a92fe22 100644 --- a/src/Mvc/Mvc.ApiExplorer/src/EndpointMetadataApiDescriptionProvider.cs +++ b/src/Mvc/Mvc.ApiExplorer/src/EndpointMetadataApiDescriptionProvider.cs @@ -274,7 +274,7 @@ private static ParameterDescriptor CreateParameterDescriptor(ParameterInfo param { return (BindingSource.FormFile, fromFormAttribute.Name ?? parameter.Name ?? string.Empty, false, parameterType); } - else if (parameter.ParameterInfo.CustomAttributes.Any(a => typeof(IFromServiceMetadata).IsAssignableFrom(a.AttributeType) || typeof(FromKeyedServicesAttribute) == a.AttributeType) || + else if (parameter.ParameterInfo.CustomAttributes.Any(a => typeof(IFromServiceMetadata).IsAssignableFrom(a.AttributeType) || typeof(FromKeyedServicesAttribute).IsAssignableFrom(a.AttributeType)) || parameterType == typeof(HttpContext) || parameterType == typeof(HttpRequest) || parameterType == typeof(HttpResponse) || diff --git a/src/Mvc/Mvc.ApiExplorer/test/DefaultApiDescriptionProviderTest.cs b/src/Mvc/Mvc.ApiExplorer/test/DefaultApiDescriptionProviderTest.cs index 9d5425384d87..a949d6cecc0b 100644 --- a/src/Mvc/Mvc.ApiExplorer/test/DefaultApiDescriptionProviderTest.cs +++ b/src/Mvc/Mvc.ApiExplorer/test/DefaultApiDescriptionProviderTest.cs @@ -8,7 +8,6 @@ using System.Globalization; using System.Reflection; using System.Text; -using System.Xml.Linq; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ActionConstraints; @@ -1521,6 +1520,20 @@ public void GetApiDescription_ParameterDescription_SourceFromServices() Assert.Empty(description.ParameterDescriptions); } + [Fact] + public void GetApiDescription_ParameterDescription_SourceFromDerivedServices() + { + // Arrange + var action = CreateActionDescriptor(nameof(AcceptsFormatters_DerivedServices)); + + // Act + var descriptions = GetApiDescriptions(action); + + // Assert + var description = Assert.Single(descriptions); + Assert.Empty(description.ParameterDescriptions); + } + [Fact] public void GetApiDescription_ParameterDescription_SourceFromCustomModelBinder() { @@ -2509,6 +2522,10 @@ private void AcceptsFormatters_Services([FromServices] ITestService tempDataProv { } + private void AcceptsFormatters_DerivedServices([CustomFromServices] ITestService tempDataProvider, [CustomFromKeyedServices("foo")] ITestService keyedTempDataProvider) + { + } + private void AcceptsProductChangeDTO(ProductChangeDTO dto) { } @@ -2953,4 +2970,8 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c return base.ConvertFrom(context, culture, value); } } + + private class CustomFromKeyedServicesAttribute(object key) : FromKeyedServicesAttribute(key); + + private class CustomFromServicesAttribute : FromServicesAttribute; } diff --git a/src/Mvc/Mvc.ApiExplorer/test/EndpointMetadataApiDescriptionProviderTest.cs b/src/Mvc/Mvc.ApiExplorer/test/EndpointMetadataApiDescriptionProviderTest.cs index 7de4d5eb5b89..16d525cbcb4e 100644 --- a/src/Mvc/Mvc.ApiExplorer/test/EndpointMetadataApiDescriptionProviderTest.cs +++ b/src/Mvc/Mvc.ApiExplorer/test/EndpointMetadataApiDescriptionProviderTest.cs @@ -795,7 +795,9 @@ public void DoesNotAddFromServiceParameterAsService() { Assert.Empty(GetApiDescription((IInferredServiceInterface foo) => { }).ParameterDescriptions); Assert.Empty(GetApiDescription(([FromServices] InferredServiceClass foo) => { }).ParameterDescriptions); + Assert.Empty(GetApiDescription(([CustomFromServices] InferredServiceClass foo) => { }).ParameterDescriptions); Assert.Empty(GetApiDescription(([FromKeyedServices("foo")] InferredServiceClass foo) => { }).ParameterDescriptions); + Assert.Empty(GetApiDescription(([CustomFromKeyedServices("foo")] InferredServiceClass foo) => { }).ParameterDescriptions); Assert.Empty(GetApiDescription((HttpContext context) => { }).ParameterDescriptions); Assert.Empty(GetApiDescription((HttpRequest request) => { }).ParameterDescriptions); Assert.Empty(GetApiDescription((HttpResponse response) => { }).ParameterDescriptions); @@ -1918,4 +1920,8 @@ private class TestServiceProvider : IServiceProvider } private class GenericClass { public required TType Value { get; set; } } + + private class CustomFromKeyedServicesAttribute(object key) : FromKeyedServicesAttribute(key); + + private class CustomFromServicesAttribute : FromServicesAttribute; } diff --git a/src/OpenApi/src/Services/OpenApiGenerator.cs b/src/OpenApi/src/Services/OpenApiGenerator.cs index fd56a779dc88..8ed8d075062e 100644 --- a/src/OpenApi/src/Services/OpenApiGenerator.cs +++ b/src/OpenApi/src/Services/OpenApiGenerator.cs @@ -424,7 +424,7 @@ private List GetOpenApiParameters(MethodInfo methodInfo, Rout { return (true, null, null); } - else if (parameter.CustomAttributes.Any(a => typeof(IFromServiceMetadata).IsAssignableFrom(a.AttributeType) || typeof(FromKeyedServicesAttribute) == a.AttributeType) || + else if (parameter.CustomAttributes.Any(a => typeof(IFromServiceMetadata).IsAssignableFrom(a.AttributeType) || typeof(FromKeyedServicesAttribute).IsAssignableFrom(a.AttributeType)) || parameter.ParameterType == typeof(HttpContext) || parameter.ParameterType == typeof(HttpRequest) || parameter.ParameterType == typeof(HttpResponse) || diff --git a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiGeneratorTests.cs b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiGeneratorTests.cs index 3dbf13d3995f..0dc6f3f6e53d 100644 --- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiGeneratorTests.cs +++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiGeneratorTests.cs @@ -413,7 +413,9 @@ public void DoesNotAddFromServiceParameterAsService() { Assert.Empty(GetOpenApiOperation((IInferredServiceInterface foo) => { }).Parameters); Assert.Empty(GetOpenApiOperation(([FromServices] int foo) => { }).Parameters); + Assert.Empty(GetOpenApiOperation(([CustomFromServices] int foo) => { }).Parameters); Assert.Empty(GetOpenApiOperation(([FromKeyedServices("foo")] int foo) => { }).Parameters); + Assert.Empty(GetOpenApiOperation(([CustomFromKeyedServices("foo")] int foo) => { }).Parameters); Assert.Empty(GetOpenApiOperation((HttpContext context) => { }).Parameters); Assert.Empty(GetOpenApiOperation((HttpRequest request) => { }).Parameters); Assert.Empty(GetOpenApiOperation((HttpResponse response) => { }).Parameters); @@ -1144,4 +1146,8 @@ public override Endpoint Build() throw new NotImplementedException(); } } + + private class CustomFromKeyedServicesAttribute(object key) : FromKeyedServicesAttribute(key); + + private class CustomFromServicesAttribute : FromServicesAttribute; }