-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
There appears to be inconsistent behavior when passing json format data containing enum values to a .net core minimal api. There is a mismatch between what is described in the open api schema and the behavior of the application.
When a valid json containing a list of enum values where the enum values are inside a single string, the enum values are parsed with Flags behavior even though the enum is not annotated as a Flags enum.
In the following code example, when the json body
"{ "numbers": ["one, two"]}"
is passed to the api, the resulting enum is
"three"
{
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.MapNumbersEndpoints();
app.Run();
public enum Number { zero, one, two, three}
public record SomeNumbers(List<Number> Numbers);
public static class NumbersEndpoints
{
public static void MapNumbersEndpoints(this WebApplication app)
{
app.MapPost("/numbers", (SomeNumbers someNumbers) => Results.Ok(new { Message = ListNumbers(someNumbers) }));
}
private static string ListNumbers(SomeNumbers someNumbers)
{
return string.Join(", ", someNumbers.Numbers);
}
}
[TestClass]
public class NumbersEndpointTests
{
[TestMethod]
public async Task PostSomeNumbers_DoesNotReturnTheCombinationOfInputValues()
{
// Arrange
await using var application = new WebApplicationFactory<Program>();
using var client = application.CreateClient();
var numbersJson = "{ \"numbers\": [\"one, two\"]}";
var content = new StringContent(numbersJson, System.Text.Encoding.UTF8, "application/json");
// Act
var response = await client.PostAsync("/numbers", content);
// Assert
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<NumbersResponse>();
Assert.IsNotNull(result);
Assert.AreNotEqual("three", result.Message);
}
private record NumbersResponse(string Message);
}
}
The created api documentation also does not seem to reflect this behavior.
Here, the description of the enum without Flags annotation:
{
"components": {
"schemas": {
"Number": {
"enum": [
"zero",
"one",
"two",
"three"
]
},
}
and with Flags annotation:
{
"components": {
"schemas": {
"Number": {
"type": "string"
},
}
A user of this api could now screw up his data or inject invalid data by accident. This then becomes a very interesting debugging experience as this is quite an unexpected behavior.
A enum that is not annotated as a Flags enum should not be parsed into a Flags enum. This behavior is completely unexpected while the enum is also not prepared to be a Flags enum. Also, it is a mismatch between what is presented in the open api schema and the runtime bahavior.
To me, it feels like a BadRequest response should be returned in such a case.