Search code examples
c#jsondynamicsystem.text.json

System.Text.Json Serializing dynamic object, won't ignore nulls


I need to serialize a dynamic to JSON but want to suppress all null properties (the actual use case is executing a SQL query with results going into a dynamic and having many null columns).

Not having any luck with System.Text.Json.JsonSerializer.Serialize(), no matter which JsonIgnoreCondition value I use in the options. The JsonIgnoreCondition option works fine for actual types, just not on a dynamic.

using System.Dynamic;
using System.Text.Json.Serialization;
using System.Text.Json;

var foo = new Foo();
var fooJson = JsonSerializer.Serialize(foo, new JsonSerializerOptions() { WriteIndented = true});
var fooJson1 = JsonSerializer.Serialize(foo, new JsonSerializerOptions() { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault});
var fooJson2 = JsonSerializer.Serialize(foo, new JsonSerializerOptions() {WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull});

Console.WriteLine("fooJson:");
Console.WriteLine(fooJson);
Console.WriteLine("fooJson1:");
Console.WriteLine(fooJson1);
Console.WriteLine("fooJson2:");
Console.WriteLine(fooJson2);

dynamic dynamicFoo = new ExpandoObject();
dynamicFoo.Prop1 = "something";
dynamicFoo.Prop2 = (int?)null;
dynamicFoo.Prop3 = (string)null;

var dynamicFooJson = JsonSerializer.Serialize(dynamicFoo, new JsonSerializerOptions() { WriteIndented = true});
var dynamicFooJson1 = JsonSerializer.Serialize(dynamicFoo, new JsonSerializerOptions() { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault});
var dynamicFooJson2 = JsonSerializer.Serialize(dynamicFoo, new JsonSerializerOptions() {WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull});

Console.WriteLine("dynamicFooJson:");
Console.WriteLine(dynamicFooJson);
Console.WriteLine("dynamicFooJson1:");
Console.WriteLine(dynamicFooJson1);
Console.WriteLine("dynamicFooJson2:");
Console.WriteLine(dynamicFooJson2);


public class Foo
{
    public string Prop1 {get;set;}
    public int Prop2 {get;set;}
    public int? Prop3 {get;set;}
}

Produces the following output

fooJson:
{
  "Prop1": null,
  "Prop2": 0,
  "Prop3": null
}
fooJson1:
{}
fooJson2:
{
  "Prop2": 0
}
dynamicFooJson:
{
  "Prop1": "something",
  "Prop2": null,
  "Prop3": null
}
dynamicFooJson1:
{
  "Prop1": "something",
  "Prop2": null,
  "Prop3": null
}
dynamicFooJson2:
{
  "Prop1": "something",
  "Prop2": null,
  "Prop3": null
}

Solution

  • The workaround / solution seems to hinge on the fact that a dynamic is really just an IDictionary<string, object> (thanks, @MySkullCaveIsADarkPlace) - so a custom JsonConverter that ignores null values in the dictionary works great.

    public class DynamicConverter : JsonConverter<IDictionary<string, object>>
    {
        public override IDictionary<string, object>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }
    
        public override void Write(Utf8JsonWriter writer, IDictionary<string, object> value, JsonSerializerOptions options)
        {
            writer.WriteStartObject();
            foreach (var val in value)
            {
                if (val.Value != null)
                {
                    writer.WritePropertyName(val.Key);
                    JsonSerializer.Serialize(writer, val.Value, options);
                }
            }
            writer.WriteEndObject();
        }
    }