Search code examples
c#json.net-6.0system.text.jsonjsonserializer

How to ignore empty strings in API JSON response?


I have an API developed in .NET6. Currently, all properties that are being returned as null, are being hidden via the below:

_ = services.AddControllers().AddJsonOptions(options => {
    options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; });

I require to ignore also values that are empty string. There I have implemented the below converter:

public class EmptyStringConverter : JsonConverter<string>
{
    public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return reader.GetString()!;
    }
    public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
    {
        if (!string.IsNullOrEmpty(value))
        {
            writer.WriteStringValue(value);
        }
        else
        {
            writer.WriteNullValue();
        }
    }
}

Added the converter to the AddJsonOptions:

_ = services.AddControllers().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.Converters.Add(new EmptyStringConverter());
    options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});

The converter is working - changing empty string properties to null, but in the API response, these properties are visible, although I have set

  DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull.

I reviewed other articles stating to add the default attribute, but that means having to change all the properties of all the models, which is not feasible. Additionally, this also means that numbers with value 0, will be hidden, which is not something that I would want.

I require to use System.Text.Json rather than Newtonsoft.

Is there a way how I can achieve this please?


Solution

  • You can customize the JSON contract used by the DefaultJsonTypeInfoResolver or derived type.

    Below code changes each property of type string to only serialize when not null and not empty.

    This contract customization via property type inspection only occurs once per model type. It is the Func applied to ShouldSerialize that runs for each string property value.

    builder.Services
        .AddControllers()
        .AddJsonOptions(o => o.JsonSerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver()    
        {
            Modifiers =
            { 
                jsonTypeInfo => 
                {
                    foreach (var propertyInfo in jsonTypeInfo.Properties.Where(o => o.PropertyType == typeof(string)))
                    {
                        propertyInfo.ShouldSerialize = (parent, property) => !string.IsNullOrEmpty(property as string);
                    }
                }
            }
        });