- 
                Notifications
    You must be signed in to change notification settings 
- Fork 10.5k
Labels
area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-openapihelp wantedUp for grabs. We would accept a PR to help resolve this issueUp for grabs. We would accept a PR to help resolve this issue
Description
Is there an existing issue for this?
- I have searched the existing issues
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: 
aspnetcore/src/OpenApi/src/Services/Schemas/OpenApiSchemaService.cs
Lines 172 to 215 in a6ce940
| 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
Metadata
Metadata
Assignees
Labels
area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-openapihelp wantedUp for grabs. We would accept a PR to help resolve this issueUp for grabs. We would accept a PR to help resolve this issue