From f4439a2a9b02e650f78bbc8ead38150962b64f87 Mon Sep 17 00:00:00 2001 From: Brennan Date: Wed, 21 May 2025 11:25:54 -0700 Subject: [PATCH 1/2] Fix OpenApiJsonSchema array parsing --- .../src/Schemas/OpenApiJsonSchema.Helpers.cs | 1 + .../OpenApiSchemaService.ParameterSchemas.cs | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs b/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs index 46b8fab926a6..b9c70c94028e 100644 --- a/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs +++ b/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs @@ -140,6 +140,7 @@ internal sealed partial class OpenApiJsonSchema { type = JsonSchemaType.Array; var array = new JsonArray(); + reader.Read(); while (reader.TokenType != JsonTokenType.EndArray) { array.Add(ReadJsonNode(ref reader)); diff --git a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.ParameterSchemas.cs b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.ParameterSchemas.cs index cf0b7b018902..d756690a4452 100644 --- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.ParameterSchemas.cs +++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.ParameterSchemas.cs @@ -722,4 +722,52 @@ public static bool TryParse(string value, out Student result) return true; } } + + // Regression test for https://github.com/dotnet/aspnetcore/issues/62023 + // Testing that the array parsing in our OpenApiJsonSchema works + [Fact] + public async Task CustomConverterThatOutputsArrayWithDefaultValue() + { + // Arrange + var serviceCollection = new ServiceCollection(); + serviceCollection.ConfigureHttpJsonOptions(options => + { + options.SerializerOptions.Converters.Add(new EnumArrayTypeConverter()); + }); + var builder = CreateBuilder(serviceCollection); + + // Act + builder.MapPost("/api", (EnumArrayType e = EnumArrayType.None) => { }); + + // Assert + await VerifyOpenApiDocument(builder, document => + { + var operation = document.Paths["/api"].Operations[HttpMethod.Post]; + var param = Assert.Single(operation.Parameters); + Assert.NotNull(param.Schema); + Assert.IsType(param.Schema.Default); + // Type is null, it's up to the user to configure this via a custom schema + // transformer for types with a converter. + Assert.Null(param.Schema.Type); + }); + } + + public enum EnumArrayType + { + None = 1 + } + + public class EnumArrayTypeConverter : JsonConverter + { + public override EnumArrayType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new EnumArrayType(); + } + + public override void Write(Utf8JsonWriter writer, EnumArrayType value, JsonSerializerOptions options) + { + writer.WriteStartArray(); + writer.WriteEndArray(); + } + } } From 788c7b802741fc200de7b4eca109f0870d496387 Mon Sep 17 00:00:00 2001 From: Brennan Date: Thu, 22 May 2025 14:25:36 -0700 Subject: [PATCH 2/2] fb --- .../src/Schemas/OpenApiJsonSchema.Helpers.cs | 1 + .../OpenApiSchemaService.ParameterSchemas.cs | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs b/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs index b9c70c94028e..1bf7ccd7921a 100644 --- a/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs +++ b/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs @@ -140,6 +140,7 @@ internal sealed partial class OpenApiJsonSchema { type = JsonSchemaType.Array; var array = new JsonArray(); + // Read to process JsonTokenType.StartArray before advancing reader.Read(); while (reader.TokenType != JsonTokenType.EndArray) { diff --git a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.ParameterSchemas.cs b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.ParameterSchemas.cs index d756690a4452..d2dae5f253aa 100644 --- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.ParameterSchemas.cs +++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Services/OpenApiSchemaService/OpenApiSchemaService.ParameterSchemas.cs @@ -752,6 +752,33 @@ await VerifyOpenApiDocument(builder, document => }); } + [Fact] + public async Task CustomConverterThatOutputsObjectWithDefaultValue() + { + // Arrange + var serviceCollection = new ServiceCollection(); + serviceCollection.ConfigureHttpJsonOptions(options => + { + options.SerializerOptions.Converters.Add(new EnumObjectTypeConverter()); + }); + var builder = CreateBuilder(serviceCollection); + + // Act + builder.MapPost("/api", (EnumArrayType e = EnumArrayType.None) => { }); + + // Assert + await VerifyOpenApiDocument(builder, document => + { + var operation = document.Paths["/api"].Operations[HttpMethod.Post]; + var param = Assert.Single(operation.Parameters); + Assert.NotNull(param.Schema); + Assert.IsType(param.Schema.Default); + // Type is null, it's up to the user to configure this via a custom schema + // transformer for types with a converter. + Assert.Null(param.Schema.Type); + }); + } + public enum EnumArrayType { None = 1 @@ -770,4 +797,18 @@ public override void Write(Utf8JsonWriter writer, EnumArrayType value, JsonSeria writer.WriteEndArray(); } } + + public class EnumObjectTypeConverter : JsonConverter + { + public override EnumArrayType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new EnumArrayType(); + } + + public override void Write(Utf8JsonWriter writer, EnumArrayType value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + writer.WriteEndObject(); + } + } }