Search code examples
c#swashbucklesystem.text.json.net-5

System.Text.Json Field Serialization in .NET 5 not shown in Swashbuckle API Definition


Problem

I'm using ASP.NET Core with .NET 5 and am using the System.Text.Json serializer to serialize types containing fields (like System.Numerics.Vector3 (X, Y and Z are fields), although any type with fields behaves the same here).

I've verified that fields get serialized properly by calling the API over Postman, however the Swagger API Definition generated by Swashbuckle does not properly reflect this. (The definition just shows an empty type)

Repro

I've created a gist that reproduces this. It provides an HTTP Get method at /api/Test which returns an object of Type Test with a field and a property. Both are strings. Calling this API via Postman returns the correct values for both. Viewing the Swagger UI at /swagger or the definition at /swagger/v1/swagger.json only shows the property.

This behaviour applies to the examples in the Swagger UI as well, which only include the properties.

Expected behaviour

According to the docs the Swagger Generator should automatically copy the behaviour of System.Text.Json, which is explicitly configured to serialize fields (see line 47), so I'd expect the Swagger definition to include the field.

Summary

To reiterate, I use System.Text.Json to serialize a type with public fields. This works, and I'd prefer keeping it like this.

I try to use Swashbuckle to generate documentation of the API that returns these serializations. This only works for properties, but not fields.

Is there something else that needs to be explicitly configured for this to work?


Solution

  • It seems like Swashbuckle doesn't use the JsonSerializerOptions to generate the docs. One workaround i found is to handle the types manually:

    public class FieldsSchemaFilter : ISchemaFilter
    {
        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            var fields = context.Type.GetFields();
    
            if (fields == null) return;
            if (fields.Length == 0) return;
    
            foreach (var field in fields)
            {
                schema.Properties[field.Name] = new OpenApiSchema
                {
                    // this should be mapped to an OpenApiSchema type
                    Type = field.FieldType.Name
                };
            }
        }
    }
    

    Then in your Startup.cs ConfigureServices:

    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication1", Version = "v1" });
        c.SchemaFilter<FieldsSchemaFilter>();
    });
    

    When stepping through, you'll see the JsonSerializerOptions used in the SchemaFilterContext (SchemaGenerator). IncludeFields is set to true. Still only properties are used for docs, so I guess a filter like that is your best bet.