
有小伙伴反馈,System.Text.Json使用的序列化问题,经了解是System.Text.Json不兼容System.Runtime.Serialization.DataMemenber属性标记
来个demo,
1 var testMode = new TestMode(); 2 testMode.ID = "aaa"; 3 var serialize = JsonSerializer.Serialize(testMode); 4 Debug.WriteLine(serialize); 5 6 [DataContract] 7 public class TestMode 8 { 9 [DataMember(Name = "id")] 10 public string ID { get; set; } 11 }
所以DataMember是不适用system.Text.Json的。
我们梳理下各序列化方案下如何正确的使用属性标记
DataContract及DataMemenber
System.Runtime.Serialization下,有数据契约序列化DataContractSerializer,可以用于XML序列化及WCF数据传输
而它的胞弟Json序列化DataContractJsonSerializer,是早期 的.NET Json序列化方案。因性能较弱,Framework下大家逐渐使用NewtonSoft.Json来替换。但简单的Json序列化,依然可以使用DataContractJsonSerializer
DataContractJsonSerializer使用的属性标记是DataContract、DataMember,DataContract用于标记类,DataMember标记序列化的属性:
1 var stopwatch = new Stopwatch(); 2 stopwatch.Start(); 3 var serializer = new DataContractJsonSerializer(typeof(TestMode)); 4 using (var stream = new MemoryStream()) 5 { 6 serializer.WriteObject(stream, testMode); 7 string json = Encoding.UTF8.GetString(stream.ToArray()); 8 Console.WriteLine($"{json},{stopwatch.ElapsedMilliseconds}ms"); 9 }
Newtonsoft.Json是兼容DataContract、DataMember的,所以使用Newtonsoft.Json.JsonConvert可以正常的进行对DataMember的属性进行序列化。:
1 stopwatch.Restart(); 2 var serializeObject = JsonConvert.SerializeObject(testMode); 3 Console.WriteLine($"{serializeObject},{stopwatch.ElapsedMilliseconds}ms");
Newtonsoft.Json内部是通过默认配置JsonConvert.DefaultSettings,来兼容DataContract标记,
1 var settings = new JsonSerializerSettings 2 { 3 ContractResolver = new DefaultContractResolver 4 { 5 IgnoreSerializableAttribute = false // 启用 DataContract 支持 6 } 7 };
Newtonsoft.Json虽然对DataMember兼容,但DataContract标记需要注意下:类加DataContract标记后,则只支持有标记DataMember的属性序列化。
输出结果:
DataMember均序列化正常。另外可以发现,在.NET Framework及.NET版本下,首次序列化性能DataContractJsonSerializer比NewtonSoft.Json好很多
System.Text.Json被称作现代Json序列化,System.Text.Json 不识别 [DataMember],如果必须兼容可通过自定义 JsonConverter 间接支持,但复杂。。不推荐
补充下DataMember使用的其它相关标记:
[IgnoreDataMember] – 忽略字段
[DataMember]EmitDefaultValue、Order、IsRequired – 控制默认值、排序、是否必填
我个人挺喜欢用DataContract的,可以明确标记序列化类,与业务数据类隔离开来。
JsonPropertyName
JsonPropertyName是System.Text.Json.Serialization命名空间下的Attribute类,只适用于JsonSerializer序列化方案
微软官方推荐使用,性能比Newtonsoft.Json更好。性能对比可参考 .NET Json序列化方案选择 – 唐宋元明清2188 – 博客园
也补充相关属性标记:
[JsonIgnore] – 忽略属性
[JsonRequired] – 必填
[JsonInclude] – 强制包含如private的私有字段
JsonProperty
JsonProerty是Newtonsoft.Json第三方组件下的属性标记类,专属Newtonsoft.Json-JsonConvert序列化方案
补充相关属性标记
[JsonIgnore] – 忽略属性
[JsonRequired] – 必填
Newtonsoft.Json与System.Text.Json属性标记很相似,不要混用了。
多框架下的属性标记
如果你的组件添加了.NETFramework以及.NET多个框架版本,因考虑不同框架下的最佳Json序列化性能,那你的序列化属性类可能就需要处理不同的属性标记了
同时给一个属性添加多个标记能解决问题:
1 [JsonProperty("id")] 2 [JsonPropertyName("id")] 3 [DataMember(Name = "id",)] 4 public string ID { get; set; }
但不建议,容易造成后续维护的风险,可能不小心就遗漏了一个。
最佳方案是,通过明确的框架类型来区分不同代码
引用组件:
1 #if NETFRAMEWORK 2 using Newtonsoft.Json; 3 #elif NET8_0 4 using System.Text.Json.Serialization; 5 #endif
添加序列化属性标记:
1 #if NETFRAMEWORK 2 [JsonProperty("id")] 3 #elif NET8_0 4 [JsonPropertyName("id")] 5 #endif
一个框架下,建议明确并统一使用一个序列化方案。性能对比可参考 .NET Json序列化方案选择 – 唐宋元明清2188 – 博客园