[英]Deserialize a object containing a nested json string with escaped characters to a nested POCO
我們正在接收 json 消息,其中包含帶有轉義字符的嵌入式 json 對象。
例如,轉義的 Json string rawMessage = "{\"lte\": \"{\\\"lst\\\":5,\\\"lrs\\\":19,\\\"lrq\\\":3}\"}";
這顯然很快就很難測試,並且可能會出現無數的打字錯誤,因此我們希望找到一種更簡潔的方式來處理 POCO 而不是原始字符串。 不幸的是,反序列化嵌入的消息並不是直截了當的。
上面的字符串具有以下等效模型:
public class Message{
public string lte { get; set;}
}
在代碼中使用它,我們可以執行JsonConvert.DeserializeObject<Message>(rawMessage)
,它將字符串反序列化為 Message 模型,如果我們將鼠標懸停在調試器中的 lte 上,則會顯示嵌入的 Json。
我想做的是反序列化為完整的 POCO,即:
public class Message{
public Lte lte { get; set;}
}
public class Lte{
public int lst { get; set;}
public int lrs { get; set;}
public int lrq { get; set;}
}
但是,當JsonConvert.DeserializeObject<Message>(rawMessage)
時,這會導致轉換異常。
有趣的是,如果你反序列化兩次,嵌入的 json 轉換就可以了。 回到 Message 的字符串版本,你可以運行:
var message = JsonConvert.DeserializeObject<Message>(rawMessage);
var embeddedMessage = JsonConvert.DeserializeObject<Lte>(message.lte);
檢索嵌入的 POCO。
一次反序列化調用是否可能,也許只是缺少一些裝飾器?
解決方案是編寫自定義JsonConverter
。
如果我理解正確,您正在使用Newtonsoft.Json
。 這是您的模型的自定義 JSON 轉換器:
public class MessageConverter : JsonConverter<Message> {
public override void WriteJson(JsonWriter writer, Message value, JsonSerializer serializer) {
writer.WriteToken(JsonToken.StartObject);
writer.WritePropertyName("lte");
writer.WriteValue(JsonConvert.SerializeObject(value.lte));
writer.WriteToken(JsonToken.EndObject);
}
public override Message ReadJson(JsonReader reader,
Type objectType,
Message existingValue,
bool hasExistingValue,
JsonSerializer serializer) {
string? lteString = null;
while (reader.Read()) {
if (reader.TokenType == JsonToken.PropertyName && (string)reader.Value! == "lte") {
lteString = reader.ReadAsString();
break;
}
}
while(reader.Read()) {}
if (lteString is null) {
throw new JsonException("lte property missing");
}
return new Message { lte = JsonConvert.DeserializeObject<Lte>(lteString) };
}
}
用法:
string rawMessage = "{\"lte\": \"{\\\"lst\\\":5,\\\"lrs\\\":19,\\\"lrq\\\":3}\"}";
var message = JsonConvert.DeserializeObject<Message>(rawMessage, new MessageConverter());
更新
您還可以將[JsonConverter(typeof(MessageConverter))]
應用於Message
類:
[JsonConverter(typeof(MessageConverter))]
public class Message {
public Lte lte { get; set; }
}
string rawMessage = "{\"lte\": \"{\\\"lst\\\":5,\\\"lrs\\\":19,\\\"lrq\\\":3}\"}";
var message = JsonConvert.DeserializeObject<Message>(rawMessage);
這樣你就不需要每次都使用new MessageConverter()
。
更新
我想出了一個更簡單的解決方案。 只為Lte
編寫一個轉換器,並通過屬性直接在lte
屬性的Message
類中應用它。 看起來更簡潔並且允許安全地擴展Message
類而無需修改轉換器:
public class Message {
[JsonConverter(typeof(LteConverter))]
public Lte lte { get; set; }
}
public class Lte {
public int lst { get; set; }
public int lrs { get; set; }
public int lrq { get; set; }
}
public class LteConverter : JsonConverter<Lte> {
public override void WriteJson(JsonWriter writer, Lte value, JsonSerializer serializer) {
writer.WriteValue(JsonConvert.SerializeObject(value));
}
public override Lte ReadJson(JsonReader reader,
Type objectType,
Lte existingValue,
bool hasExistingValue,
JsonSerializer serializer) {
return JsonConvert.DeserializeObject<Lte>((string)reader.Value!);
}
}
用法:
string rawMessage = "{\"lte\": \"{\\\"lst\\\":5,\\\"lrs\\\":19,\\\"lrq\\\":3}\"}";
var message = JsonConvert.DeserializeObject<Message>(rawMessage);
你可以先解析,之后你可以反序列化
var lteJson = (string) JObject.Parse(rawMessage)["lte"];
Lte lte = JsonConvert.DeserializeObject<Lte>(lteJson);
或者只是一行
Lte lte = JsonConvert.DeserializeObject<Lte>((string)JObject.Parse(rawMessage)["lte"]);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.