Added ValueTask support to API Explorer response types. (#13739)

(cherry picked from commit 24b051de5ee386521f8b286c7c7d4f69ac1f2244)

Fixes https://github.com/aspnet/AspNetCore/issues/4883
This commit is contained in:
Travis Illig 2019-09-06 12:13:42 -07:00 committed by Pranav K
parent f9c15caa7a
commit f1f615282d
2 changed files with 69 additions and 3 deletions

View File

@ -214,7 +214,8 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
{ {
var declaredReturnType = action.MethodInfo.ReturnType; var declaredReturnType = action.MethodInfo.ReturnType;
if (declaredReturnType == typeof(void) || if (declaredReturnType == typeof(void) ||
declaredReturnType == typeof(Task)) declaredReturnType == typeof(Task) ||
declaredReturnType == typeof(ValueTask))
{ {
return typeof(void); return typeof(void);
} }
@ -222,7 +223,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
// Unwrap the type if it's a Task<T>. The Task (non-generic) case was already handled. // Unwrap the type if it's a Task<T>. The Task (non-generic) case was already handled.
var unwrappedType = declaredReturnType; var unwrappedType = declaredReturnType;
if (declaredReturnType.IsGenericType && if (declaredReturnType.IsGenericType &&
declaredReturnType.GetGenericTypeDefinition() == typeof(Task<>)) (declaredReturnType.GetGenericTypeDefinition() == typeof(Task<>) || declaredReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)))
{ {
unwrappedType = declaredReturnType.GetGenericArguments()[0]; unwrappedType = declaredReturnType.GetGenericArguments()[0];
} }

View File

@ -472,6 +472,22 @@ namespace Microsoft.AspNetCore.Mvc.Description
Assert.NotNull(responseType.ModelMetadata); Assert.NotNull(responseType.ModelMetadata);
} }
[Fact]
public void GetApiDescription_PopulatesResponseType_WithValueTaskOfProduct()
{
// Arrange
var action = CreateActionDescriptor(nameof(ReturnsValueTaskOfProduct));
// Act
var descriptions = GetApiDescriptions(action);
// Assert
var description = Assert.Single(descriptions);
var responseType = Assert.Single(description.SupportedResponseTypes);
Assert.Equal(typeof(Product), responseType.Type);
Assert.NotNull(responseType.ModelMetadata);
}
[Theory] [Theory]
[InlineData(nameof(ReturnsObject))] [InlineData(nameof(ReturnsObject))]
[InlineData(nameof(ReturnsActionResult))] [InlineData(nameof(ReturnsActionResult))]
@ -479,6 +495,9 @@ namespace Microsoft.AspNetCore.Mvc.Description
[InlineData(nameof(ReturnsTaskOfObject))] [InlineData(nameof(ReturnsTaskOfObject))]
[InlineData(nameof(ReturnsTaskOfActionResult))] [InlineData(nameof(ReturnsTaskOfActionResult))]
[InlineData(nameof(ReturnsTaskOfJsonResult))] [InlineData(nameof(ReturnsTaskOfJsonResult))]
[InlineData(nameof(ReturnsValueTaskOfObject))]
[InlineData(nameof(ReturnsValueTaskOfActionResult))]
[InlineData(nameof(ReturnsValueTaskOfJsonResult))]
public void GetApiDescription_DoesNotPopulatesResponseInformation_WhenUnknown(string methodName) public void GetApiDescription_DoesNotPopulatesResponseInformation_WhenUnknown(string methodName)
{ {
// Arrange // Arrange
@ -521,7 +540,7 @@ namespace Microsoft.AspNetCore.Mvc.Description
}, },
{ {
typeof(DefaultApiDescriptionProviderTest), typeof(DefaultApiDescriptionProviderTest),
nameof(DefaultApiDescriptionProviderTest.ReturnsActionResult), nameof(DefaultApiDescriptionProviderTest.ReturnsValueTaskOfActionResult),
filterDescriptors filterDescriptors
}, },
{ {
@ -624,6 +643,11 @@ namespace Microsoft.AspNetCore.Mvc.Description
nameof(DefaultApiDescriptionProviderTest.ReturnsTask), nameof(DefaultApiDescriptionProviderTest.ReturnsTask),
filterDescriptors filterDescriptors
}, },
{
typeof(DefaultApiDescriptionProviderTest),
nameof(DefaultApiDescriptionProviderTest.ReturnsValueTask),
filterDescriptors
},
{ {
typeof(DerivedProducesController), typeof(DerivedProducesController),
nameof(DerivedProducesController.ReturnsVoid), nameof(DerivedProducesController.ReturnsVoid),
@ -634,6 +658,11 @@ namespace Microsoft.AspNetCore.Mvc.Description
nameof(DerivedProducesController.ReturnsTask), nameof(DerivedProducesController.ReturnsTask),
filterDescriptors filterDescriptors
}, },
{
typeof(DerivedProducesController),
nameof(DerivedProducesController.ReturnsValueTask),
filterDescriptors
},
}; };
} }
} }
@ -895,6 +924,7 @@ namespace Microsoft.AspNetCore.Mvc.Description
[Theory] [Theory]
[InlineData(nameof(ReturnsVoid))] [InlineData(nameof(ReturnsVoid))]
[InlineData(nameof(ReturnsTask))] [InlineData(nameof(ReturnsTask))]
[InlineData(nameof(ReturnsValueTask))]
public void GetApiDescription_DefaultVoidStatus(string methodName) public void GetApiDescription_DefaultVoidStatus(string methodName)
{ {
// Arrange // Arrange
@ -914,6 +944,7 @@ namespace Microsoft.AspNetCore.Mvc.Description
[Theory] [Theory]
[InlineData(nameof(ReturnsVoid))] [InlineData(nameof(ReturnsVoid))]
[InlineData(nameof(ReturnsTask))] [InlineData(nameof(ReturnsTask))]
[InlineData(nameof(ReturnsValueTask))]
public void GetApiDescription_VoidWithResponseTypeAttributeStatus(string methodName) public void GetApiDescription_VoidWithResponseTypeAttributeStatus(string methodName)
{ {
// Arrange // Arrange
@ -944,6 +975,10 @@ namespace Microsoft.AspNetCore.Mvc.Description
[InlineData(nameof(ReturnsTask))] [InlineData(nameof(ReturnsTask))]
[InlineData(nameof(ReturnsTaskOfActionResult))] [InlineData(nameof(ReturnsTaskOfActionResult))]
[InlineData(nameof(ReturnsTaskOfJsonResult))] [InlineData(nameof(ReturnsTaskOfJsonResult))]
[InlineData(nameof(ReturnsValueTask))]
[InlineData(nameof(ReturnsValueTaskOfObject))]
[InlineData(nameof(ReturnsValueTaskOfActionResult))]
[InlineData(nameof(ReturnsValueTaskOfJsonResult))]
public void GetApiDescription_PopulatesResponseInformation_WhenSetByFilter(string methodName) public void GetApiDescription_PopulatesResponseInformation_WhenSetByFilter(string methodName)
{ {
// Arrange // Arrange
@ -2026,6 +2061,31 @@ namespace Microsoft.AspNetCore.Mvc.Description
return null; return null;
} }
private ValueTask<Product> ReturnsValueTaskOfProduct()
{
return default;
}
private ValueTask<object> ReturnsValueTaskOfObject()
{
return default;
}
private ValueTask ReturnsValueTask()
{
return default;
}
private ValueTask<IActionResult> ReturnsValueTaskOfActionResult()
{
return default;
}
private ValueTask<JsonResult> ReturnsValueTaskOfJsonResult()
{
return default;
}
private Product ReturnsProduct() private Product ReturnsProduct()
{ {
return null; return null;
@ -2196,6 +2256,11 @@ namespace Microsoft.AspNetCore.Mvc.Description
return null; return null;
} }
public ValueTask ReturnsValueTask()
{
return default;
}
public void ReturnsVoid() public void ReturnsVoid()
{ {
} }