[英]Json deserialization class structure on client
我无法在客户端端点上反序列化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;
}
那也不起作用。
这里有两个问题。 首先,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.