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
}
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();
}
}