Skip to content

Commit 20d4a00

Browse files
authored
MVC: Correct metadata type for formdata enum parameters (#61399)
1 parent d5d2a31 commit 20d4a00

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

src/Mvc/Mvc.ApiExplorer/src/EndpointModelMetadata.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public static Type GetDisplayType(Type type)
6565
|| underlyingType == typeof(TimeSpan)
6666
|| underlyingType == typeof(decimal)
6767
|| underlyingType == typeof(Guid)
68-
|| underlyingType == typeof(Uri) ? type : typeof(string);
68+
|| underlyingType == typeof(Uri)
69+
|| underlyingType.IsEnum ? type : typeof(string);
6970
}
7071
}

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiDocumentServiceTestsBase.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using Microsoft.AspNetCore.Mvc.Formatters;
1616
using Microsoft.AspNetCore.Mvc.Infrastructure;
1717
using Microsoft.AspNetCore.Mvc.ModelBinding;
18+
using Microsoft.AspNetCore.Mvc.Routing;
1819
using Microsoft.AspNetCore.OpenApi;
1920
using Microsoft.AspNetCore.Routing;
2021
using Microsoft.AspNetCore.Routing.Constraints;
@@ -234,8 +235,13 @@ public ControllerActionDescriptor CreateActionDescriptor(string methodName = nul
234235
};
235236
action.RouteValues.Add("controller", "Test");
236237
action.RouteValues.Add("action", action.MethodInfo.Name);
237-
action.ActionConstraints = [new HttpMethodActionConstraint(["GET"])];
238238
action.EndpointMetadata = [..action.MethodInfo.GetCustomAttributes()];
239+
action.ActionConstraints = [new HttpMethodActionConstraint(action
240+
.EndpointMetadata
241+
.OfType<IActionHttpMethodProvider>()
242+
.SelectMany(a => a.HttpMethods)
243+
.DefaultIfEmpty("GET")
244+
)];
239245
if (controllerType is not null)
240246
{
241247
foreach (var attribute in controllerType.GetCustomAttributes())

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.RequestBodySchemas.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,4 +708,51 @@ public class Parent
708708
public IDictionary<string, Parent> SelfReferenceDictionary { get; set; } = new Dictionary<string, Parent>();
709709
}
710710

711+
/// <remarks>
712+
/// Regression test for https://github.com/dotnet/aspnetcore/issues/61327
713+
/// </remarks>
714+
[Fact]
715+
public async Task RespectsEnumDefaultValueInControllerFormParameters()
716+
{
717+
// Arrange
718+
var actionDescriptor = CreateActionDescriptor(nameof(TestBodyController.FormPostWithOptionalEnumParam), typeof(TestBodyController));
719+
720+
// Assert
721+
await VerifyOpenApiDocument(actionDescriptor, VerifyOptionalEnum);
722+
}
723+
724+
[Fact]
725+
public async Task RespectsEnumDefaultValueInMinimalApiFormParameters()
726+
{
727+
// Arrange
728+
var builder = CreateBuilder();
729+
730+
// Act
731+
builder.MapPost("/optionalEnum", ([FromForm(Name = "status")] Status status = Status.Approved) => { });
732+
733+
// Assert
734+
await VerifyOpenApiDocument(builder, VerifyOptionalEnum);
735+
}
736+
737+
private void VerifyOptionalEnum(OpenApiDocument document)
738+
{
739+
var operation = document.Paths["/optionalEnum"].Operations[HttpMethod.Post];
740+
var properties = operation.RequestBody.Content["application/x-www-form-urlencoded"].Schema.Properties;
741+
var property = properties["status"];
742+
743+
Assert.NotNull(property);
744+
Assert.Equal(3, property.Enum.Count);
745+
Assert.Equal("Approved", property.Default.GetValue<string>());
746+
}
747+
748+
[ApiController]
749+
[Produces("application/json")]
750+
public class TestBodyController
751+
{
752+
[Route("/optionalEnum")]
753+
[HttpPost]
754+
internal Status FormPostWithOptionalEnumParam(
755+
[FromForm(Name = "status")] Status status = Status.Approved
756+
) => status;
757+
}
711758
}

0 commit comments

Comments
 (0)