Skip to content

OpenApi ignores JsonNumberHandling.WriteAsString #58882

Open
@adrianm64

Description

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When a property has the attribute JsonNumberHandling(JsonNumberHandling.AllowReadingFromString|JsonNumberHandling.WriteAsString), OpenApi still describes the property with the native type and not a string

Expected Behavior

When using JsonNumberHandling.WriteAsString I expect the OpenApi specification to report the propery as string

"prop": {
    "type": "string",
 }

Steps To Reproduce

  1. Create a new default asp.net webapi for dotnet 9.
  2. Run the project and navigate to /openapi/v1.json
  3. The temperatureC property is listed as integer:
"temperatureC": {
    "type": "integer",
     "format": "int32"
},  
  1. In weatherforcast.cs add an attribute to the temperatureC property
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString|JsonNumberHandling.WriteAsString)]
public int TemperatureC { get; set; }
  1. Run the project and navigate to /weatherforecast and see temperatureC is a string.
[{"date":"2024-11-12","temperatureC":"11","temperatureF":51,"summary":"Balmy"},{"date":"2024-11-13","temperatureC":"3","temperatureF":37,"summary":"Warm"}}
  1. Navigate to /openapi/v1.json
  2. The temperatureC property is still listed as an integer:
"temperatureC": {
    "type": "integer",
    "format": "int32"
},  

Exceptions (if any)

No response

.NET Version

9.0.100-rc.1.24452.12

Anything else?

A workaround is to add a SchemaTransformer like

internal sealed class JsonNumberHandlerSchemaTransformer : IOpenApiSchemaTransformer
{
    public Task TransformAsync(OpenApiSchema schema, OpenApiSchemaTransformerContext context, CancellationToken cancellationToken)
    {
        var properties = context.JsonTypeInfo.Type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                .Where(prop => prop.GetCustomAttribute<JsonNumberHandlingAttribute>()?.Handling.HasFlag(JsonNumberHandling.WriteAsString) ?? false)
                                .Select(prop => prop.GetCustomAttribute<JsonPropertyNameAttribute>()?.Name ?? 
                                                context.JsonTypeInfo.Options.PropertyNamingPolicy?.ConvertName(prop.Name) ??
                                                prop.Name)
                                .Where(schema.Properties.ContainsKey);

        foreach (var property in properties)
        {
            schema.Properties[property].Type = "string";
        }

        return Task.CompletedTask;
    }
}

but this is using reflection and probably missing some other details.

Metadata

Assignees

No one assigned

    Labels

    area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-openapi

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions