簡體   English   中英

將包含帶有轉義字符的嵌套 json 字符串的對象反序列化為嵌套的 POCO

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM