diff --git a/src/Mvc/Mvc.ApiExplorer/src/EndpointModelMetadata.cs b/src/Mvc/Mvc.ApiExplorer/src/EndpointModelMetadata.cs index 3fd46f1798e2..d893d3a04b01 100644 --- a/src/Mvc/Mvc.ApiExplorer/src/EndpointModelMetadata.cs +++ b/src/Mvc/Mvc.ApiExplorer/src/EndpointModelMetadata.cs @@ -65,6 +65,7 @@ public static Type GetDisplayType(Type type) || underlyingType == typeof(TimeSpan) || underlyingType == typeof(decimal) || underlyingType == typeof(Guid) - || underlyingType == typeof(Uri) ? type : typeof(string); + || underlyingType == typeof(Uri) + || underlyingType.IsEnum ? type : typeof(string); } } diff --git a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiDocumentServiceTestsBase.cs b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiDocumentServiceTestsBase.cs index aa2246385b31..a788ecb7d335 100644 --- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiDocumentServiceTestsBase.cs +++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiDocumentServiceTestsBase.cs @@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.OpenApi; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Constraints; @@ -235,8 +236,13 @@ public ControllerActionDescriptor CreateActionDescriptor(string methodName = nul }; action.RouteValues.Add("controller", "Test"); action.RouteValues.Add("action", action.MethodInfo.Name); - action.ActionConstraints = [new HttpMethodActionConstraint(["GET"])]; action.EndpointMetadata = [..action.MethodInfo.GetCustomAttributes()]; + action.ActionConstraints = [new HttpMethodActionConstraint(action + .EndpointMetadata + .OfType() + .SelectMany(a => a.HttpMethods) + .DefaultIfEmpty("GET") + )]; if (controllerType is not null) { foreach (var attribute in controllerType.GetCustomAttributes()) diff --git a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.RequestBodySchemas.cs b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.RequestBodySchemas.cs index e62eff7d94df..45784c5f6f64 100644 --- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.RequestBodySchemas.cs +++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.RequestBodySchemas.cs @@ -710,4 +710,51 @@ public class Parent public IDictionary SelfReferenceDictionary { get; set; } = new Dictionary(); } + /// + /// Regression test for https://github.com/dotnet/aspnetcore/issues/61327 + /// + [Fact] + public async Task RespectsEnumDefaultValueInControllerFormParameters() + { + // Arrange + var actionDescriptor = CreateActionDescriptor(nameof(TestBodyController.FormPostWithOptionalEnumParam), typeof(TestBodyController)); + + // Assert + await VerifyOpenApiDocument(actionDescriptor, VerifyOptionalEnum); + } + + [Fact] + public async Task RespectsEnumDefaultValueInMinimalApiFormParameters() + { + // Arrange + var builder = CreateBuilder(); + + // Act + builder.MapPost("/optionalEnum", ([FromForm(Name = "status")] Status status = Status.Approved) => { }); + + // Assert + await VerifyOpenApiDocument(builder, VerifyOptionalEnum); + } + + private void VerifyOptionalEnum(OpenApiDocument document) + { + var operation = document.Paths["/optionalEnum"].Operations[OperationType.Post]; + var properties = operation.RequestBody.Content["application/x-www-form-urlencoded"].Schema.Properties; + var property = properties["status"]; + + Assert.NotNull(property); + Assert.Equal(3, property.Enum.Count); + Assert.Equal("Approved", property.Default.GetValue()); + } + + [ApiController] + [Produces("application/json")] + public class TestBodyController + { + [Route("/optionalEnum")] + [HttpPost] + internal Status FormPostWithOptionalEnumParam( + [FromForm(Name = "status")] Status status = Status.Approved + ) => status; + } }