.NET中如何反序列化含无字段值的JSON数组?
如何反序列化混合类型的JSON数组到.NET对象
问题场景
我正在开发一个从特定Web服务获取JSON消息的应用,返回的JSON是混合类型数组:
[ 15, "5667", { "status":"Uploaded", "uploadTime":"2023-07-05T11:03:19+00:00", "progress":12 } ]
我尝试用以下.NET类直接反序列化:
public class WebServiceNotification{ public int typeId { get; set; } public string msgId { get; set; } public string status { get; set; } public string uploadTime{ get; set; } public int progress{ get; set; } }
使用Newtonsoft.Json和System.Text.Json均失败,测试代码如下(已修正字符串引号转义问题):
string msgFromWebService = "[15,\"5667\",{\"status\":\"Uploaded\",\"uploadTime\":\"2023-07-05T11:03:19+00:00\",\"progress\":12}]"; var ocppMsg1 = JsonSerializer.Deserialize<WebServiceNotification>(msgFromWebService); var ocppMsg2 = JsonConvert.DeserializeObject<WebServiceNotification>(msgFromWebService);
报错信息
- System.Text.Json报错:
Unhandled exception. System.Text.Json.JsonException: '1' is an invalid start of a property name. Expected a '"'. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
- Newtonsoft.Json报错:
Unhandled exception. Newtonsoft.Json.JsonReaderException: Invalid JavaScript property identifier character: ,. Path '', line 1, position 3.
核心问题:能否反序列化这种包含无对应字段纯值(如15和"5667")的JSON消息?
解决方案
可以实现反序列化。问题根源是你试图将JSON数组直接映射到**.NET对象**,两者结构不匹配。需要通过拆分数组元素或自定义转换器来完成映射。
方法1:手动拆分数组元素映射(快速实现)
先将JSON反序列化为数组,再将数组元素逐个赋值到目标类。
使用System.Text.Json
var jsonArray = JsonSerializer.Deserialize<object[]>(msgFromWebService); if (jsonArray != null && jsonArray.Length >=3) { var notification = new WebServiceNotification { typeId = Convert.ToInt32(jsonArray[0]), msgId = jsonArray[1] as string, status = ((JsonElement)jsonArray[2]).GetProperty("status").GetString(), uploadTime = ((JsonElement)jsonArray[2]).GetProperty("uploadTime").GetString(), progress = ((JsonElement)jsonArray[2]).GetProperty("progress").GetInt32() }; }
使用Newtonsoft.Json
var jsonArray = JsonConvert.DeserializeObject<JArray>(msgFromWebService); if (jsonArray != null && jsonArray.Count >=3) { var notification = new WebServiceNotification { typeId = jsonArray[0].Value<int>(), msgId = jsonArray[1].Value<string>(), status = jsonArray[2]["status"].Value<string>(), uploadTime = jsonArray[2]["uploadTime"].Value<string>(), progress = jsonArray[2]["progress"].Value<int>() }; }
方法2:自定义JsonConverter(优雅复用)
如果需要频繁处理这类JSON,可自定义转换器,让序列化库直接将数组映射到目标类。
针对System.Text.Json的转换器
public class WebServiceNotificationConverter : JsonConverter<WebServiceNotification> { public override WebServiceNotification Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException("JSON格式应为数组"); reader.Read(); // 跳过数组起始标记 var notification = new WebServiceNotification(); // 读取第一个元素:typeId if (reader.TokenType == JsonTokenType.Number) { notification.typeId = reader.GetInt32(); reader.Read(); } // 读取第二个元素:msgId if (reader.TokenType == JsonTokenType.String) { notification.msgId = reader.GetString(); reader.Read(); } // 读取第三个元素:嵌套对象 if (reader.TokenType == JsonTokenType.StartObject) { var obj = JsonSerializer.Deserialize<JsonElement>(ref reader, options); notification.status = obj.GetProperty("status").GetString(); notification.uploadTime = obj.GetProperty("uploadTime").GetString(); notification.progress = obj.GetProperty("progress").GetInt32(); reader.Read(); // 跳过对象结束标记 } reader.Read(); // 跳过数组结束标记 return notification; } public override void Write(Utf8JsonWriter writer, WebServiceNotification value, JsonSerializerOptions options) { // 如需序列化回JSON数组,实现对应逻辑 writer.WriteStartArray(); writer.WriteNumberValue(value.typeId); writer.WriteStringValue(value.msgId); writer.WriteStartObject(); writer.WriteString("status", value.status); writer.WriteString("uploadTime", value.uploadTime); writer.WriteNumber("progress", value.progress); writer.WriteEndObject(); writer.WriteEndArray(); } }
使用方式:
var options = new JsonSerializerOptions(); options.Converters.Add(new WebServiceNotificationConverter()); var ocppMsg = JsonSerializer.Deserialize<WebServiceNotification>(msgFromWebService, options);
针对Newtonsoft.Json的转换器
public class WebServiceNotificationConverter : JsonConverter<WebServiceNotification> { public override WebServiceNotification ReadJson(JsonReader reader, Type objectType, WebServiceNotification existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.TokenType != JsonToken.StartArray) throw new JsonReaderException("JSON格式应为数组"); var notification = new WebServiceNotification(); reader.Read(); // 跳过数组起始标记 // 读取typeId if (reader.TokenType == JsonToken.Integer) { notification.typeId = (int)reader.Value; reader.Read(); } // 读取msgId if (reader.TokenType == JsonToken.String) { notification.msgId = (string)reader.Value; reader.Read(); } // 读取嵌套对象 if (reader.TokenType == JsonToken.StartObject) { var obj = JObject.Load(reader); notification.status = obj["status"].Value<string>(); notification.uploadTime = obj["uploadTime"].Value<string>(); notification.progress = obj["progress"].Value<int>(); reader.Read(); // 跳过对象结束标记 } reader.Read(); // 跳过数组结束标记 return notification; } public override void WriteJson(JsonWriter writer, WebServiceNotification value, JsonSerializer serializer) { // 如需序列化回JSON数组,实现对应逻辑 writer.WriteStartArray(); writer.WriteValue(value.typeId); writer.WriteValue(value.msgId); writer.WriteStartObject(); writer.WritePropertyName("status"); writer.WriteValue(value.status); writer.WritePropertyName("uploadTime"); writer.WriteValue(value.uploadTime); writer.WritePropertyName("progress"); writer.WriteValue(value.progress); writer.WriteEndObject(); writer.WriteEndArray(); } }
使用方式:
var ocppMsg = JsonConvert.DeserializeObject<WebServiceNotification>(msgFromWebService, new WebServiceNotificationConverter());
内容的提问来源于stack exchange,提问作者murselmurga
相关产品推荐
相关产品推荐

