Open ascott18 opened 1 day ago
Did some fiddling as we too meet this problem, but without circular references.
Crafted the most minimal repro I could:
[ApiController]
[Route("[controller]")]
public class BadSchemaController : ControllerBase
{
public record Root(Branch Prop1, Branch Prop2, Branch Prop3);
public record Branch(Thing Thing);
public record Thing();
[HttpGet(Name = "GetBadSchema")]
public Root Get() => throw new NotImplementedException();
}
This results in the type Branch2
, which is used by Prop2 and Prop3.
Interestingly, if public record Branch(Thing Thing)
is replaced by public record Branch(string StringThing)
, the problem does not occur.
.NET 9.0.100 with <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
Okay so OpenaApiSchemaService.CreateSchema
calls into System.Text.Json.JsonSchemaExporter.GetJsonSchemaAsNode
, which calls MapJsonSchemaCore
.
During processing of Prop1, everything goes normally and we get a {Type = Branch, Kind = Object}
.
Subsequent processing will short-circuit in MapJsonSchemaCore
since state.TryGetExistingJsonPointer()
will succeed, so new JsonSchema { Ref = existingJsonPointer }
is returned. Type is never changed, so it defaults to JsonSchemaType.Any
, which at some point becomes null back in OpenApi-land.
Back in the OpenApiSchemaService when trying to add Prop2, equality is checked with OpenApiSchemaComparer.Equals
(OpenApiSchemaStore.AddOrUpdateSchemaByReference() {... if (SchemasByReference.TryGetValue(schema, out var referenceId) || captureSchemaByRef) ... }
where SchemasByReference
has the schema comparer as its equality comparer)
The very first check after null-checks and reference equality checks in OpenApiSchemaComparer.Equals
is x.Type == y.Type
. This fails since "object" == null
is false), the objects are deemed not the same, and SchemasByReference[schema] = $"{targetReferenceId}{counter}"
puts us in duplicate-land.
I'm not sure if this actually points in the right direction towards a solution (naïve idea being to set the Type when returning the Ref JsonSchema), I was just bored during my lunch break and wanted to look a bit deeper into it.
Is there an existing issue for this?
Describe the bug
A very simple circular/recursive data model produces a ton of duplicate schema definitions like
Object
,Object2
,Object3
,Object4
, and so on.Expected Behavior
Each class in C# is represented in the OpenAPI schema only once, as was the case with Swashbuckle.
Steps To Reproduce
/openapi/v1.json
ChildObject2
,ParentObject2
,ParentObject3
, which shouldn't exist..NET Version
9.0.100
Anything else?
In my real-world application, the worst offending model has been duplicated 39 times: