[英]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.