System.Text.Json序列化dynamic对象时无法忽略null值的问题
序列化Dynamic对象时忽略Null属性的解决方案
我需要将dynamic对象(实际场景是SQL查询结果存入dynamic对象,包含大量null列)序列化为JSON时,抑制所有null属性。但使用System.Text.Json.JsonSerializer.Serialize()时,不管设置哪种JsonIgnoreCondition选项都无效——这个选项对强类型有效,但对dynamic对象(比如ExpandoObject)不起作用。
复现代码
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;} }
执行输出
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 }
解决方案
方法1:手动过滤Null值
ExpandoObject实现了IDictionary<string, object>接口,可先转为字典过滤掉值为null的项,再序列化:
dynamic dynamicFoo = new ExpandoObject(); dynamicFoo.Prop1 = "something"; dynamicFoo.Prop2 = (int?)null; dynamicFoo.Prop3 = (string)null; // 过滤null值 var filteredDict = ((IDictionary<string, object>)dynamicFoo) .Where(kv => kv.Value != null) .ToDictionary(kv => kv.Key, kv => kv.Value); var json = JsonSerializer.Serialize(filteredDict, new JsonSerializerOptions { WriteIndented = true }); Console.WriteLine(json);
输出:
{ "Prop1": "something" }
方法2:自定义全局JsonConverter
如果需要统一处理所有ExpandoObject的序列化,可自定义转换器跳过null值:
public class ExpandoObjectNullIgnoringConverter : JsonConverter<ExpandoObject> { public override ExpandoObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var dict = JsonSerializer.Deserialize<Dictionary<string, object>>(ref reader, options); var expando = new ExpandoObject() as IDictionary<string, object>; if (dict != null) { foreach (var kv in dict) { expando.Add(kv); } } return (ExpandoObject)expando; } public override void Write(Utf8JsonWriter writer, ExpandoObject value, JsonSerializerOptions options) { writer.WriteStartObject(); foreach (var kv in value as IDictionary<string, object>) { if (kv.Value != null) { writer.WritePropertyName(kv.Key); JsonSerializer.Serialize(writer, kv.Value, options); } } writer.WriteEndObject(); } }
使用方式:
var options = new JsonSerializerOptions { WriteIndented = true, Converters = { new ExpandoObjectNullIgnoringConverter() } }; var json = JsonSerializer.Serialize(dynamicFoo, options); Console.WriteLine(json);
内容的提问来源于stack exchange,提问作者Mr. T
相关产品推荐
相关产品推荐

