c# - Parsing Multidimensional JSON Array with Name Value Pairs using Newtonsoft Json.NET -


i having difficulty deserializing json string sent javascript asp.net 4.52 c# web api storing database. json string originated multidimensional javascript array battleship game writing. data represents cell positions ship on x/y coordinate grid. in array/string have 5 ships , each ship have varying number of x/y positions (in form of name-value pairs example: row 3; column 3) string below data received c# webapi , represents multiple dimension javascript array data being sent via ajax httppost

shipandpositions (my json string):

var shipandpositions = "[\"ship5\",[{\"row\":4,\"col\":6},{\"row\":5,\"col\":6},{\"row\":6,\"col\":6}],\"ship4\",[{\"row\":3,\"col\":8},{\"row\":3,\"col\":9},{\"row\":3,\"col\":10},{\"row\":3,\"col\":11}],\"ship3\",[{\"row\":8,\"col\":2},{\"row\":8,\"col\":3},{\"row\":8,\"col\":4},{\"row\":8,\"col\":5}],\"ship2\",[{\"row\":9,\"col\":7},{\"row\":9,\"col\":8},{\"row\":9,\"col\":9},{\"row\":9,\"col\":10},{\"row\":9,\"col\":11}],\"ship1\",[{\"row\":0,\"col\":0},{\"row\":0,\"col\":1},{\"row\":0,\"col\":2},{\"row\":0,\"col\":3},{\"row\":0,\"col\":4},{\"row\":0,\"col\":5}],\"ship0\",[{\"row\":12,\"col\":5},{\"row\":12,\"col\":6},{\"row\":12,\"col\":7},{\"row\":12,\"col\":8},{\"row\":12,\"col\":9},{\"row\":13,\"col\":5},{\"row\":13,\"col\":6},{\"row\":13,\"col\":7},{\"row\":13,\"col\":8},{\"row\":13,\"col\":9}]]" 

this string valid json according jsonlint.com

i have defined class as:

public class coordpoints {     public string row { get; set; }      public string col { get; set; } }  public class coordpointsarray {     public string ship { get; set; }      //public list<coordpoints> shippositions { get; set; }     public dictionary<string, coordpoints[]> coordpoints { get; private set; } } 

i have newtonsoft.json.dll 4.5.8 installed have tried of following , throw exceptions

1) datacontractjsonserializer jsonobjectcoordsinfo = new datacontractjsonserializer(typeof(coordpointsarray)); memorystream stream = new memorystream(encoding.utf8.getbytes(data.shipandpositions)); coordpointsarray test1 (coordpointsarray)jsonobjectcoordsinfo.readobject(stream);

2) var shippositionlist = serializer.deserialize(data.shipandpositions);

3) var test3 = jsonconvert.deserializeobject(data.shipandpositions);

4) coordpointsarray rootobject = new coordpointsarray(); rootobject = jsonconvert.deserializeobject(data. shipandpositions);

i have tried many other variations. can me solve problem.

what have here not multidimensional array. instead, have collection of properties of collection of objects presented flat list. if format json string readability, looks like:

[   "ship5",   [{"row":4,"col":6},{"row":5,"col":6},{"row":6,"col":6}],   "ship4",   [{"row":3,"col":8},{"row":3,"col":9},{"row":3,"col":10},{"row":3,"col":11}],   "ship3",   [{"row":8,"col":2},{"row":8,"col":3},{"row":8,"col":4},{"row":8,"col":5}],   "ship2",   [{"row":9,"col":7},{"row":9,"col":8},{"row":9,"col":9},{"row":9,"col":10},{"row":9,"col":11}],   "ship1",   [{"row":0,"col":0},{"row":0,"col":1},{"row":0,"col":2},{"row":0,"col":3},{"row":0,"col":4},{"row":0,"col":5}],   "ship0",   [{"row":12,"col":5},{"row":12,"col":6},{"row":12,"col":7},{"row":12,"col":8},{"row":12,"col":9},{"row":13,"col":5},{"row":13,"col":6},{"row":13,"col":7},{"row":13,"col":8},{"row":13,"col":9}] ] 

with proper formatting, can see fits following pattern:

[     object1property1value,     object1property2value,      object2property1value,     object2property2value,      object3property1value,     object3property2value, ] 

what deserialize flat list of properties list<t> type t has properties corresponding values single portion of flat list above.

firstly, not particularly way represent data. structure of json should reflect structure of data, not true in case. better format list of json objects, or @ worst array of arrays of values of each object (in case use json.net deserialize json, making use of objecttoarrayconverter<coordpointsarray> parsing json c# object - properties dynamically.)

that being said, if cannot change json format, json can deserialized using json.net via custom jsonconverter. first, define data model follows:

public class coordpoint {     public int row { get; set; }     public int col { get; set; } }  public class coordpointsarray {     [jsonproperty(order = 1)]     public string name { get; set; }      [jsonproperty(order = 2)]     public list<coordpoint> coordinates { get; set; } } 

notice [jsonproperty(order = x)] attributes? indicate custom converter order in property values appear in json.

next, define following converter:

public class objectlisttosequentialpropertyarrayconverter<t> : jsonconverter {     public override bool canconvert(type objecttype)     {         return typeof(t) == objecttype.getlisttype();     }      static bool shouldskip(jsonproperty property)     {         return property.ignored || !property.readable || !property.writable;     }      public override void writejson(jsonwriter writer, object value, jsonserializer serializer)     {         var objecttype = value.gettype();         var itemtype = objecttype.getlisttype();         if (itemtype == null)             throw new argumentexception(objecttype.tostring());         var itemcontract = serializer.contractresolver.resolvecontract(itemtype) jsonobjectcontract;         if (itemcontract == null)             throw new jsonserializationexception("invalid type " + objecttype.fullname);         var list = (ilist)value;         var propertylist = list             .oftype<object>()             .where(i => != null) // or should throw exception?             .selectmany(i => itemcontract.properties.where(p => !shouldskip(p)).select(p => p.valueprovider.getvalue(i)));         serializer.serialize(writer, propertylist);     }      public override object readjson(jsonreader reader, type objecttype, object existingvalue, jsonserializer serializer)     {         var itemtype = objecttype.getlisttype();         if (itemtype == null)             throw new argumentexception(objecttype.tostring());         if (reader.tokentype == jsontoken.null)             return null;         var array = jarray.load(reader);         var listcontract = serializer.contractresolver.resolvecontract(objecttype) jsonarraycontract;         var itemcontract = serializer.contractresolver.resolvecontract(itemtype) jsonobjectcontract;         if (itemcontract == null || listcontract == null)             throw new jsonserializationexception("invalid type " + objecttype.fullname);         var list = existingvalue ilist ?? (ilist)listcontract.defaultcreator();         var properties = itemcontract.properties.where(p => !shouldskip(p)).toarray();          (int startindex = 0; startindex < array.count; startindex += properties.length)         {             var item = itemcontract.defaultcreator();             (int iproperty = 0; iproperty < properties.length; iproperty++)             {                 if (startindex + iproperty >= array.count)                     break;                 var propertyvalue = array[startindex + iproperty].toobject(properties[iproperty].propertytype, serializer);                 properties[iproperty].valueprovider.setvalue(item, propertyvalue);             }             list.add(item);         }         return list;     } }  public static class typeextensions {     public static type getlisttype(this type type)     {         while (type != null)         {             if (type.isgenerictype)             {                 var gentype = type.getgenerictypedefinition();                 if (gentype == typeof(list<>))                     return type.getgenericarguments()[0];             }             type = type.basetype;         }         return null;     } } 

finally, deserialize json follows:

var settings = new jsonserializersettings {     converters = { new objectlisttosequentialpropertyarrayconverter<coordpointsarray>() }, };  var root = jsonconvert.deserializeobject<list<coordpointsarray>>(json, settings); 

working .net fiddle showing deserialization , re-serialization format.

note have tested json.net versions 10 (the current version) , 6 (on https://dotnetfiddle.net/) not 4.5.8.


Comments

Popular posts from this blog

ubuntu - PHP script to find files of certain extensions in a directory, returns populated array when run in browser, but empty array when run from terminal -

php - How can i create a user dashboard -

javascript - How to detect toggling of the fullscreen-toolbar in jQuery Mobile? -