c# - Json deserialization class structure on client -
i unable deserialize json data on client end point. receives json data this:
{ "waitforclientmessagesresult": [ { "__type": "keepalivemessage:#data.webgateway", "messageid": 1, "type": 0, "positioninqueue": -1 } ] } keepalivemessage derived class of webresponsemessage. service returns ienumerable<webresponsemessage>.
i'm getting exceptions this:
newtonsoft.json.jsonserializationexception:
cannot deserialize current json object (e.g. {"name":"value"}) type 'system.collections.generic.ienumerable`1[ red5prototype.models.waitforclientmessagesresult]
because type requires json array (e.g. [1,2,3]) deserialize correctly.
i've tried calling deserialization many ways:
waitforclientmessagesresult deserialized = jsonconvert.deserializeobject<waitforclientmessagesresult>(keepaliveresult);waitforclientmessagesresult[] deserialized = jsonconvert.deserializeobject<waitforclientmessagesresult[]>(keepaliveresult);ienumerable<webclientmessage> deserialized = jsonconvert.deserializeobject<ienumerable<webclientmessage>>(keepaliveresult);
none if these work.
i'm not sure how structure classes on client end use json deserializer.
edit: base class defined this:
[knowntype(typeof(keepalivemessage))] [datacontract] public abstract class webclientmessage { public webclientmessage() { } [datamember] public int messageid { get; set; } [datamember] public webclientmessagetype type { get; set; } } with keepalive this:
[datacontract] public class keepalivemessage : webclientmessage { public keepalivemessage() { } [datamember] public int positioninqueue { get; set; } } i tried making webclientmessage member of waitforclientmessagesresult
[datacontract] public class waitforclientmessagesresult { public waitforclientmessagesresult() {} [datamember] webclientmessage [] messages; } that didn't work either.
there 2 issues here. firstly, json root object has array-valued property named waitforclientmessagesresult not messages need 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, json contains polymorphic type hints in datacontractjsonserializer format. json serializer using, json.net, does not support format. therefore, might consider switching datacontractjsonserializer. using able deserialize json 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, test:
public static void test() { // note there cannot space between "{" , "_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 want stick json.net need write own jsonconverter parses "__type" property , deserializes correct concrete type.
Comments
Post a Comment