dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.57k stars 10.05k forks source link

.NET 9 OpenApi: JSON schema generation is not supported for contracts using ReferenceHandler.Preserve #58943

Open nicolaiarocci opened 1 week ago

nicolaiarocci commented 1 week ago

Is there an existing issue for this?

Describe the bug

Upgrading a .NET 8 Minimal API to .NET 9 and switching from Swashbuckle.AspNetCore to built-in Open API support, we get the following exception:

System.NotSupportedException: JSON schema generation is not supported for contracts using ReferenceHandler.Preserve.

Indeed, we have references preserved in our JSON options:

public static void AddJsonOptions(this WebApplicationBuilder builder)
    {
        builder.Services.Configure<JsonOptions>(options =>
        {
            options.SerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
            options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower;
            options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
        });
    }

By commenting out the ReferenceHandler.Preserve, the open api document is created as expected.

Expected Behavior

Support for contracts using ReferenceHandler.Preserve.

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

9.0.100

Anything else?

No response

captainsafia commented 1 week ago

@nicolaiarocci Thanks for filing this issue!

@eiriktsarpalis Is there a particular reason we opted not to generate schemas when ReferenceHandler.Preserve = true?

It seems like the schemas that Swashbuckle creates ignore the ReferenceHandler setting altogether:

"Person": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "child": {
            "$ref": "#/components/schemas/Person"
          },
          "parent": {
            "$ref": "#/components/schemas/Person"
          }
        },
        "additionalProperties": false
      },

for:

class Person
{
    public string? Name { get; set; }
    public Person? Child { get; set; }
    public Person? Parent { get; set; }
}
eiriktsarpalis commented 1 week ago

Reference preservation alters the schema for most types, notably with collections that end up wrapping their values in JSON objects. Support for it was cut in .NET 9 for lack of time, but it's conceivable that it could be added in the future provided there is demand.

eiriktsarpalis commented 1 week ago

I should add that enabling reference preservation in your app carries important security ramifications. It should only be used with trusted inputs produced by System.Text.Json. In my opinion, it is not appropriate to use reference preservation in the context of web apps or Open API.