使用Newtonsoft Json.NET序列化对象结构不符合第三方接口预期
问题:满足第三方接口的XML和JSON序列化要求(含重复属性的JSON格式)
需求说明
需要将数据序列化为符合第三方接口要求的XML和JSON格式,预期结果如下:
预期XML格式
<?xml version="1.0" encoding="utf-8"?> <FooList> <Foo> <Name>George</Name> <Color>Blue</Color> </Foo> <Foo> <Name>Betty</Name> <Color>Green</Color> </Foo> </FooList>
预期JSON格式
[ { "Foo": { "Name": "George", "Color": "Blue" }, "Foo": { "Name": "Betty", "Color": "Green" } } ]
注:第三方接口要求JSON包含重复的"Foo"属性名,尽管这不符合常规JSON规范,但必须满足该要求。
当前实现的数据模型
已创建以下C#类用于序列化:
[Serializable, XmlType(AnonymousType = true), XmlRoot(Namespace = "", ElementName = "FooList", IsNullable = false)] public class FooListResponse { [XmlElement("Foo", IsNullable = false)] public List<Foo> FooList { get; set; } } [Serializable] public class Foo { [XmlElement("Name"), JsonProperty("Name")] public string Name { get; set; } [XmlElement("Color"), JsonProperty("Color")] public string Color { get; set; } }
当前序列化问题
- XML序列化结果符合预期;
- 使用Newtonsoft Json.NET的
JsonConvert.SerializeObject序列化时,结果不符合要求:{ "FooList": [ { "Name": "George", "Color": "Blue" }, { "Name": "Betty", "Color": "Green" } ] } - 尝试仅序列化
FooList属性,结果仍不符合要求:
缺少外层大括号及每个对象前的[ { "Name": "George", "Color": "Blue" }, { "Name": "Betty", "Color": "Green" } ]"Foo:"标识,且无法生成重复的"Foo"属性。需要无需重复定义数据模型的解决方案,因为实际模型远比示例复杂。
解决方案:自定义JsonConverter
通过为FooListResponse类编写自定义Json转换器,实现符合要求的JSON序列化,无需修改现有模型:
1. 实现自定义转换器
public class FooListResponseJsonConverter : JsonConverter<FooListResponse> { public override void WriteJson(JsonWriter writer, FooListResponse value, JsonSerializer serializer) { // 写入外层数组 writer.WriteStartArray(); // 写入数组内的对象 writer.WriteStartObject(); // 为每个Foo对象写入重复的"Foo"属性 foreach (var foo in value.FooList) { writer.WritePropertyName("Foo"); serializer.Serialize(writer, foo); } writer.WriteEndObject(); writer.WriteEndArray(); } public override FooListResponse ReadJson(JsonReader reader, Type objectType, FooListResponse existingValue, bool hasExistingValue, JsonSerializer serializer) { // 实现反序列化逻辑(按需使用) var response = new FooListResponse { FooList = new List<Foo>() }; if (reader.TokenType == JsonToken.StartArray) { reader.Read(); // 进入数组内的对象 if (reader.TokenType == JsonToken.StartObject) { while (reader.Read() && reader.TokenType == JsonToken.PropertyName) { if ((string)reader.Value == "Foo") { var foo = serializer.Deserialize<Foo>(reader); response.FooList.Add(foo); } else { reader.Skip(); // 跳过非Foo属性 } } } } return response; } }
2. 使用转换器进行序列化
// 构造测试数据 var fooListResponse = new FooListResponse { FooList = new List<Foo> { new Foo { Name = "George", Color = "Blue" }, new Foo { Name = "Betty", Color = "Green" } } }; // 配置序列化设置,添加自定义转换器 var jsonSettings = new JsonSerializerSettings(); jsonSettings.Converters.Add(new FooListResponseJsonConverter()); // 序列化生成符合要求的JSON string json = JsonConvert.SerializeObject(fooListResponse, jsonSettings);
最终生成的JSON
运行上述代码后,将得到完全符合第三方要求的JSON格式:
[ { "Foo": { "Name": "George", "Color": "Blue" }, "Foo": { "Name": "Betty", "Color": "Green" } } ]
内容的提问来源于stack exchange,提问作者Michael Hartmann
相关产品推荐
相关产品推荐

