2015-04-28 123 views
2

我无法反序列化客户端上的JSON数据。它接收JSON数据是这样的:客户端上的Json反序列化类结构

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

KeepAliveMessage是派生类的WebResponseMessage。该服务返回IEnumerable<WebResponseMessage>

我得到的例外是这样的:

Newtonsoft.Json.JsonSerializationException:

不能反序列化JSON当前对象(例如{ “名”: “值”})到 型“ 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; } 
} 

与保持连接是这样的:

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

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

我试图使WebClientMessage的成员WaitForClientMessagesResult

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

    [DataMember] 
    WebClientMessage [] Messages; 
} 

这也没有效果。

+0

显示我们WaitForClientMessagesResult'是如何'声明。 –

+0

你需要使用'__type'属性吗?如果是的话,这会变得更复杂 –

+0

__type字段来自web服务,我不能改变。它使用.NET序列化。 – tatmanblue

回答

0

下面是我最终解决这个问题的方法。它有点黑客攻击,但将有现在要做的:

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处理。如果有更好的方法,我会在稍后探讨。

日Thnx大家的帮助:)我不能在这里得到了一个没有你的反馈

马特

0

这里有两个问题。首先,JSON根对象都有一个名为WaitForClientMessagesResultMessages所以你需要做这样的事情的数组值的属性:

[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格式polymorphic type hints。您正在使用的JSON序列化程序,Json.NET,does not support this format。因此,您可以考虑切换到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"属性并反序列化正确的具体类型。

+0

谢谢。这就说得通了。 – tatmanblue

相关问题