Values of additionalProperties not transformed · Issue #59616 · dotnet/aspnetcore (original) (raw)

Is there an existing issue for this?

Describe the bug

When an endpoint returns a type containing a Dictionary containing another type, the schema of this last type is not processed by schema transformers (see the missing "a": "b" in Bar2 below, causing a new schema to be created).

{ "schemas": { "Bar": { "type": "object", "properties": { "value": { "type": "integer", "format": "int32", "a": "b" } }, "a": "b" }, "Bar2": { "type": "object", "properties": { "value": { "type": "integer", "format": "int32" } } }, "Foo": { "type": "object", "properties": { "bar": { "$ref": "#/components/schemas/Bar" }, "bars": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/Bar2" }, "a": "b" } }, "a": "b" } } }

My guess is that additionalProperties should be processed somewhere here:

private async Task InnerApplySchemaTransformersAsync(OpenApiSchema schema,
JsonTypeInfo jsonTypeInfo,
JsonPropertyInfo? jsonPropertyInfo,
OpenApiSchemaTransformerContext context,
IOpenApiSchemaTransformer transformer,
CancellationToken cancellationToken = default)
{
context.UpdateJsonTypeInfo(jsonTypeInfo, jsonPropertyInfo);
await transformer.TransformAsync(schema, context, cancellationToken);
// Only apply transformers on polymorphic schemas where we can resolve the derived
// types associated with the base type.
if (schema.AnyOf is { Count: > 0 } && jsonTypeInfo.PolymorphismOptions is not null)
{
var anyOfIndex = 0;
foreach (var derivedType in jsonTypeInfo.PolymorphismOptions.DerivedTypes)
{
var derivedJsonTypeInfo = _jsonSerializerOptions.GetTypeInfo(derivedType.DerivedType);
if (schema.AnyOf.Count <= anyOfIndex)
{
break;
}
await InnerApplySchemaTransformersAsync(schema.AnyOf[anyOfIndex], derivedJsonTypeInfo, null, context, transformer, cancellationToken);
anyOfIndex++;
}
}
if (schema.Items is not null)
{
var elementTypeInfo = _jsonSerializerOptions.GetTypeInfo(jsonTypeInfo.ElementType!);
await InnerApplySchemaTransformersAsync(schema.Items, elementTypeInfo, null, context, transformer, cancellationToken);
}
if (schema.Properties is { Count: > 0 })
{
foreach (var propertyInfo in jsonTypeInfo.Properties)
{
if (schema.Properties.TryGetValue(propertyInfo.Name, out var propertySchema))
{
await InnerApplySchemaTransformersAsync(propertySchema, _jsonSerializerOptions.GetTypeInfo(propertyInfo.PropertyType), propertyInfo, context, transformer, cancellationToken);
}
}
}
}

Expected Behavior

I expected to see

{ "schemas": { "Bar": { "type": "object", "properties": { "value": { "type": "integer", "format": "int32", "a": "b" } }, "a": "b" }, "Foo": { "type": "object", "properties": { "bar": { "$ref": "#/components/schemas/Bar" }, "bars": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/Bar" }, "a": "b" } }, "a": "b" } } }

Steps To Reproduce

Add a schema transformer like so:

options.AddSchemaTransformer((schema, _, _) => { schema.Extensions.Add("a", new OpenApiString("b")); return Task.CompletedTask; });

And add an endpoint that returns a type (Foo) which contains a dictionary with another type (Bar).

app.MapGet("/", () => new Foo());

class Foo { public Bar Bar { get; set; } public Dictionary<string, Bar> Bars { get; set; } }

class Bar { public int Value { get; set; } }

Exceptions (if any)

No response

.NET Version

9.0.200-preview.0.24575.35

Anything else?

No response