簡體   English   中英

客戶端上的Json反序列化類結構

[英]Json deserialization class structure on client

我無法在客戶端端點上反序列化JSON數據。 它接收這樣的JSON數據:

{
    "WaitForClientMessagesResult": [
        {
            "__type": "KeepAliveMessage:#Data.WebGateway",
            "MessageId": 1,
            "Type": 0,
            "PositionInQueue": -1
        }
    ]
}

KeepAliveMessageWebResponseMessage的派生類。 該服務返回IEnumerable<WebResponseMessage>

我收到這樣的異常:

Newtonsoft.Json.JsonSerializationException:

無法將當前JSON對象(例如{“ name”:“ value”})反序列化為類型'System.Collections.Generic.IEnumerable`1 [Red5Prototype.Models.WaitForClientMessagesResult]

因為該類型需要JSON數組(例如[1,2,3])才能正確反序列化。

我嘗試過多種方式調用反序列化:

  • WaitForClientMessagesResult deserialized = JsonConvert.DeserializeObject<WaitForClientMessagesResult>(keepAliveResult);
  • WaitForClientMessagesResult[] deserialized = JsonConvert.DeserializeObject<WaitForClientMessagesResult[]>(keepAliveResult);
  • IEnumerable<WebClientMessage> deserialized = JsonConvert.DeserializeObject<IEnumerable<WebClientMessage>>(keepAliveResult);

如果這些有效,則無。

我不確定如何在客戶端上構造類以使用Json反序列化器。

編輯:我的基類是這樣定義的:

[KnownType(typeof(KeepAliveMessage))]    
[DataContract]
public abstract class WebClientMessage
{
    public WebClientMessage() { }

    [DataMember]
    public int MessageId { get; set; }
    [DataMember]
    public WebClientMessageType Type { get; set; }
}

與Keepalive像這樣:

[DataContract]
public class KeepAliveMessage : WebClientMessage
{
    public KeepAliveMessage() { }

    [DataMember]
    public int PositionInQueue { get; set; }
}

我試圖使WebClientMessage成為WaitForClientMessagesResult的成員

[DataContract]
public class WaitForClientMessagesResult
{
    public WaitForClientMessagesResult() {}

    [DataMember]
    WebClientMessage [] Messages;
}

那也不起作用。

這里有兩個問題。 首先,JSON根對象具有一個名為WaitForClientMessagesResult而不是Messages的數組值屬性,因此您需要執行以下操作:

[DataContract(Name = "WaitForClientMessagesResult", Namespace = "http://schemas.datacontract.org/2004/07/Data.WebGateway")]
public class WaitForClientMessagesResult
{
    public WaitForClientMessagesResult() { }

    [DataMember(Name = "WaitForClientMessagesResult")]
    public WebClientMessage[] Messages { get; set; }
}

其次,您的JSON包含DataContractJsonSerializer格式的多態類型提示 您使用的JSON序列化程序Json.NET 不支持此格式 因此,您可以考慮切換到DataContractJsonSerializer 使用它,我可以如下反序列化您的JSON:

public enum WebClientMessageType
{
    KeepAliveMessage,
}

[KnownType(typeof(KeepAliveMessage))]
[DataContract(Name="WebClientMessage", Namespace="http://schemas.datacontract.org/2004/07/Data.WebGateway")]
public abstract class WebClientMessage
{
    public WebClientMessage() { }

    [DataMember]
    public int MessageId { get; set; }

    [DataMember]
    public WebClientMessageType Type { get; set; }
}

[DataContract(Name = "KeepAliveMessage", Namespace = "http://schemas.datacontract.org/2004/07/Data.WebGateway")]
public class KeepAliveMessage : WebClientMessage
{
    public KeepAliveMessage() { }

    [DataMember]
    public int PositionInQueue { get; set; }
}

public static class DataContractJsonSerializerHelper
{
    public static string GetJson<T>(T obj, DataContractJsonSerializer serializer)
    {
        using (var memory = new MemoryStream())
        {
            serializer.WriteObject(memory, obj);
            memory.Seek(0, SeekOrigin.Begin);
            using (var reader = new StreamReader(memory))
            {
                return reader.ReadToEnd();
            }
        }
    }

    public static string GetJson<T>(T obj)
    {
        var serializer = new DataContractJsonSerializer(typeof(T));
        return GetJson(obj, serializer);
    }

    public static T GetObject<T>(string json, DataContractJsonSerializer serializer)
    {
        using (var stream = GenerateStreamFromString(json))
        {
            var obj = serializer.ReadObject(stream);
            return (T)obj;
        }
    }

    public static T GetObject<T>(string json)
    {
        var serializer = new DataContractJsonSerializer(typeof(T));
        return GetObject<T>(json, serializer);
    }

    private static MemoryStream GenerateStreamFromString(string value)
    {
        return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
    }
}

然后,進行測試:

    public static void Test()
    {
        // Note there cannot be a space between the "{" and the "_type": 
        string json = @"{
            ""WaitForClientMessagesResult"": [
                {""__type"": ""KeepAliveMessage:#Data.WebGateway"",
                    ""MessageId"": 1,
                    ""Type"": 0,
                    ""PositionInQueue"": -1
                }
            ]
        }";
        var result = DataContractJsonSerializerHelper.GetObject<WaitForClientMessagesResult>(json);
        var newJson = DataContractJsonSerializerHelper.GetJson(result);

        Debug.Assert(JToken.DeepEquals(JToken.Parse(json), JToken.Parse(newJson))); // No assert
    }

如果您想使用Json.NET,則需要編寫自己的JsonConverter來解析"__type"屬性並反序列化正確的具體類型。

這就是我最終解決此問題的方式。 這有點hack,但是現在必須這樣做:

    Dictionary<string, object> deserialized = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
    JArray messagesArray = deserialized["WaitForClientMessagesResult"] as JArray;

    foreach (JObject gatewayMessage in messagesArray.Children<JObject>())
    {
        string messageJson = gatewayMessage.ToString();
        WebClientMessageType messageType = GetMessageType(gatewayMessage);
        WaitForClientMessagesResult msg = null;

        switch (messageType)
        {
            case WebClientMessageType.KeepAlive:
                msg = JsonConvert.DeserializeObject<KeepAliveMessage>(messageJson);
                break;
            default:
                break;
        }

    }

我刪除了其他業務邏輯,並發布了Json處理信息。 如果有更好的方法,我將在以后進行探討。

謝謝大家的幫助:)沒有您的反饋,我無法到達這里

馬特

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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