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

Popular posts from this blog

java - Spring Data JPA: Why findOne(id) executing delete query internally? -

python - Mongodb How to add addtional information when aggregating? -

java - Incorrect order of records in M-M relationship in hibernate -