我无法在客户端端点反序列化JSON数据。它接收如下的JSON数据:
{
"WaitForClientMessagesResult": [
{
"__type": "KeepAliveMessage:#Data.WebGateway",
"MessageId": 1,
"Type": 0,
"PositionInQueue": -1
}
]
}
KeepAliveMessage
是WebResponseMessage
的派生类。该服务返回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;
}
这也不起作用。
答案 0 :(得分:0)
There are two issues here. Firstly, the JSON root object has an array-valued property named WaitForClientMessagesResult
not Messages
so you need to do something like this:
[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; }
}
Secondly, your JSON contains polymorphic type hints in the DataContractJsonSerializer
format. The JSON serializer you are using, Json.NET, does not support this format. Therefore, you might consider switching to DataContractJsonSerializer
. Using it I was able to deserialize your JSON as follows:
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 ?? ""));
}
}
And then, to test:
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
}
If you want to stick with Json.NET you will need to write your own JsonConverter
that parses the "__type"
property and deserializes the correct concrete type.
答案 1 :(得分: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为大家提供帮助:)没有您的反馈,我无法到达这里
马特