Json 客户端上的反序列化 class 结构
Json deserialization class structure on client
我无法反序列化客户端端点上的 JSON 数据。它接收 JSON 这样的数据:
{
"WaitForClientMessagesResult": [
{
"__type": "KeepAliveMessage:#Data.WebGateway",
"MessageId": 1,
"Type": 0,
"PositionInQueue": -1
}
]
}
KeepAliveMessage
是 WebResponseMessage
的派生 class。服务 returns 和 IEnumerable<WebResponseMessage>
.
我遇到这样的异常:
Newtonsoft.Json.JsonSerializationException:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type
'System.Collections.Generic.IEnumerable`1[
Red5Prototype.Models.WaitForClientMessagesResult]
because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
我试过很多方法调用反序列化:
WaitForClientMessagesResult deserialized = JsonConvert.DeserializeObject<WaitForClientMessagesResult>(keepAliveResult);
WaitForClientMessagesResult[] deserialized = JsonConvert.DeserializeObject<WaitForClientMessagesResult[]>(keepAliveResult);
IEnumerable<WebClientMessage> deserialized = JsonConvert.DeserializeObject<IEnumerable<WebClientMessage>>(keepAliveResult);
None 如果这些有效。
我不确定如何在客户端构建我的 classes 以使用 Json 反序列化器。
编辑:
我的基础 class 是这样定义的:
[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 包含 polymorphic type hints in the DataContractJsonSerializer
format. The JSON serializer you are using, 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"
属性 并反序列化正确的具体类型。
这是我最终解决这个问题的方法。这有点麻烦,但现在必须这样做:
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 处理。如果有更好的方法,我稍后再探讨。
谢谢大家的帮助 :) 没有你们的反馈我无法来到这里
马特
我无法反序列化客户端端点上的 JSON 数据。它接收 JSON 这样的数据:
{
"WaitForClientMessagesResult": [
{
"__type": "KeepAliveMessage:#Data.WebGateway",
"MessageId": 1,
"Type": 0,
"PositionInQueue": -1
}
]
}
KeepAliveMessage
是 WebResponseMessage
的派生 class。服务 returns 和 IEnumerable<WebResponseMessage>
.
我遇到这样的异常:
Newtonsoft.Json.JsonSerializationException:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IEnumerable`1[ Red5Prototype.Models.WaitForClientMessagesResult]
because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
我试过很多方法调用反序列化:
WaitForClientMessagesResult deserialized = JsonConvert.DeserializeObject<WaitForClientMessagesResult>(keepAliveResult);
WaitForClientMessagesResult[] deserialized = JsonConvert.DeserializeObject<WaitForClientMessagesResult[]>(keepAliveResult);
IEnumerable<WebClientMessage> deserialized = JsonConvert.DeserializeObject<IEnumerable<WebClientMessage>>(keepAliveResult);
None 如果这些有效。
我不确定如何在客户端构建我的 classes 以使用 Json 反序列化器。
编辑: 我的基础 class 是这样定义的:
[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 包含 polymorphic type hints in the DataContractJsonSerializer
format. The JSON serializer you are using, 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"
属性 并反序列化正确的具体类型。
这是我最终解决这个问题的方法。这有点麻烦,但现在必须这样做:
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 处理。如果有更好的方法,我稍后再探讨。
谢谢大家的帮助 :) 没有你们的反馈我无法来到这里
马特