Skip to content

Commit 01bda26

Browse files
committed
Fix enum handling for MVC actions to close #57979
1 parent f471d24 commit 01bda26

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

src/OpenApi/src/Services/OpenApiDocumentService.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,12 @@ private async Task<OpenApiResponse> GetResponseAsync(
402402
continue;
403403
}
404404

405+
// MVC's ModelMetadata layer will set ApiParameterDescription.Type to string when the parameter
406+
// is a parsable or convertible type. In this case, we want to use the actual model type
407+
// to generate the schema instead of the string type.
408+
var targetType = parameter.Type == typeof(string) && parameter.ModelMetadata.ModelType != parameter.Type
409+
? parameter.ModelMetadata.ModelType
410+
: parameter.Type;
405411
var openApiParameter = new OpenApiParameter
406412
{
407413
Name = parameter.Name,
@@ -413,7 +419,7 @@ private async Task<OpenApiResponse> GetResponseAsync(
413419
_ => throw new InvalidOperationException($"Unsupported parameter source: {parameter.Source.Id}")
414420
},
415421
Required = IsRequired(parameter),
416-
Schema = await _componentService.GetOrCreateSchemaAsync(parameter.Type, scopedServiceProvider, schemaTransformers, parameter, cancellationToken: cancellationToken),
422+
Schema = await _componentService.GetOrCreateSchemaAsync(targetType, scopedServiceProvider, schemaTransformers, parameter, cancellationToken: cancellationToken),
417423
Description = GetParameterDescriptionFromAttribute(parameter)
418424
};
419425

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,59 @@ await VerifyOpenApiDocument(builder, document =>
537537
Assert.Null(operation.RequestBody.Content["application/json"].Schema.Type);
538538
});
539539
}
540+
541+
[Theory]
542+
[InlineData(false)]
543+
[InlineData(true)]
544+
public async Task SupportsParameterWithEnumType(bool useAction)
545+
{
546+
// Arrange
547+
if (!useAction)
548+
{
549+
var builder = CreateBuilder();
550+
builder.MapGet("/api/with-enum", (ItemStatus status) => status);
551+
}
552+
else
553+
{
554+
var action = CreateActionDescriptor(nameof(GetItemStatus));
555+
await VerifyOpenApiDocument(action, AssertOpenApiDocument);
556+
}
557+
558+
static void AssertOpenApiDocument(OpenApiDocument document)
559+
{
560+
var operation = document.Paths["/api/with-enum"].Operations[OperationType.Get];
561+
var parameter = Assert.Single(operation.Parameters);
562+
var response = Assert.Single(operation.Responses).Value.Content["application/json"].Schema;
563+
Assert.NotNull(parameter.Schema.Reference);
564+
Assert.Equal(parameter.Schema.Reference.Id, response.Reference.Id);
565+
var schema = parameter.Schema.GetEffective(document);
566+
Assert.Collection(schema.Enum,
567+
value =>
568+
{
569+
var openApiString = Assert.IsType<OpenApiString>(value);
570+
Assert.Equal("Pending", openApiString.Value);
571+
},
572+
value =>
573+
{
574+
var openApiString = Assert.IsType<OpenApiString>(value);
575+
Assert.Equal("Approved", openApiString.Value);
576+
},
577+
value =>
578+
{
579+
var openApiString = Assert.IsType<OpenApiString>(value);
580+
Assert.Equal("Rejected", openApiString.Value);
581+
});
582+
}
583+
}
584+
585+
[Route("/api/with-enum")]
586+
private ItemStatus GetItemStatus([FromQuery] ItemStatus status) => status;
587+
588+
[JsonConverter(typeof(JsonStringEnumConverter<ItemStatus>))]
589+
internal enum ItemStatus
590+
{
591+
Pending = 0,
592+
Approved = 1,
593+
Rejected = 2,
594+
}
540595
}

0 commit comments

Comments
 (0)