How should one interpret this JSON structure? - c#

I've just started to work with JSON and after having read a few articles, I'm still unclear if I'm looking at an array, list or just an object. It looks like this.
{
"list": [{
"fields": {
"id": "9222115557374550596",
...
},
},
{
"fields": {
"id": "9222115557374550597",
...
},
}],
"paging": {
"pageCurrent": 0,
"itemMin": 0,
"itemMax": 2,
"maxNextPages": 0,
"pageSize": 100
}
}
I'd like to deserialize it to be a list (or IEnumerable) of objects typed so that there's an Id property (perhaps not all fields have to be parsed in to the object).
When I try to do that using the following code:
List<Some> somes = JsonConvert.DeserializeObject<List<Some>>(dataAbove);
class Some { public String Id { get; set; } }
I get a long error message about me not being using the correct type and array and a bunch of other stuff that makes me confused. Am I on the right track or did I totally went off and got lost?!
I understand it's something with the list at the root. But what?! Or at least - what should I google for?!
Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"}) into type 'System.Collections.Generic.List`1[ScriveProxy.Template]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.\u000d\u000aTo fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.\u000d\u000aPath 'list', line 1, position 8."
It can't be this one because the outer brackets are curly not squary...
In this solution, we end up with a single object, not an array, so it's not what I'm aiming for neither.

In your case, "list" is an array of "fields" objects.
"paging" is an object.
Both "list"` and "paging"` are in an un-named root object.
Working dotNetFiddle: https://dotnetfiddle.net/4qLTvq
See the output in the console pane of the fiddle above.
Here's How you should declare your Classes for Deserializing this particular JSON into C# Classes.
public class Fields
{
public string id { get; set; }
}
public class TheFields
{
public Fields fields { get; set; }
}
public class Paging
{
public int pageCurrent { get; set; }
public int itemMin { get; set; }
public int itemMax { get; set; }
public int maxNextPages { get; set; }
public int pageSize { get; set; }
}
public class RootObject
{
[Newtonsoft.Json.JsonPropertyAttribute("list")]
public List<TheFields> FieldsList { get; set; }
public Paging paging { get; set; }
}
And here's how you would deserialize the whole thing.
var rootObject = JsonConvert.DeserializeObject<RootObject>(jsonString);
Since List is a keyword, and to avoid confusion and collision, I changed it's Name to FieldsList and also renamed the List class to TheFields class. You may choose any other name(s) that you feel is appropriate.
Explanation on Object vs Array
An object is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace). Each name is followed by : (colon) and the name/value pairs are separated by , (comma).
An array is an ordered collection of values. An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma).
Source: http://www.json.org/

If it starts with { it's an object.
If it starts with [ it's an array.

Related

How to pass JSON string as array

[
{"id": 1, "name": "danny_devito", "img": "/images/1"},
{"id": 2, "name": "jim_carey", "img": "/images/2"},
{"id": 3, "name": "tyler_1", "img": "/images/3"}
]
[System.Serializable]
public class Players {
public int id;
public string name;
public string img;
}
[System.Serializable]
public class PlayersArray {
public Players[] playersData;
}
string playersJson = File.ReadAllText(Application.dataPath + "/playersFile.json");
PlayersArray loadedPlayerData = (PlayersArray)JsonUtility.FromJson<PlayersArray>(playersJson);
Debug.Log("Danny Boy: " + loadedPlayerData.playersData[0].name);
I followed tons of tutorials and none of it works!
It gives me this error:
You're trying to deserialize an object. But the JSON you show isn't an object. It's an array. Deserialize it into a collection:
var loadedPlayerData = JsonUtility.FromJson<List<Players>>(playersJson);
Or even just an array:
var loadedPlayerData = JsonUtility.FromJson<Players[]>(playersJson);
As an aside... Names are important. Players is a misleading name for a player. The class should be called Player instead.
Additionally, this class might not deserialize at all, depending on how the JSON serializer works. They tend to use properties, not fields. You'll likely want to use properties anyway:
public class Players {
public int id { get; set; }
public string name { get; set; }
public string img { get; set; }
}
For further improvements, you will probably also want to capitalize the property names. The JSON serializer might be case-sensitive (I don't think they tend to be by default, but it's worth testing) and you may need to add attributes to the properties to specify their names in the JSON. But just to get the code working, at the very least you'll most likely need properties here instead of fields.

How can I deserialize JSON when the object type is not known beforehand?

So I have an API and front-end that I am developing, and I need a way to deserialize JSON when one of the values could be a List of multiple different types. Currently I'm deserializing it into a List<dynamic> but that's a huge pain to work with in my context.
public class WorkbenchAPI
{
public string status { get; set; }
public HttpStatusCode code { get; set; }
public string error { get; set; }
public string guid { get; set; }
public List<dynamic> results { get; set; }
}
Sample JSON
{
"status": "ok",
"code": 200,
"error": null,
"guid": "1234",
"results": [
{
"SamAccountName": "dizbuster",
"CN": "Buster, Diz",
"EmailAddress": "dizbuster#whatever.com",
}
]
}
In the above example JSON, results should be deserialized into type List<ClassA> for example.
{
"status": "ok",
"code": 200,
"error": null,
"guid": "1234",
"results": [
{
"data": "127.0.0.1",
"owner": "dizbuster",
"email": "dizbuster#whatever.com",
},
{
"data": "192.168.0.1",
"owner": "dizbuster",
"email": "dizbuster#whatever.com",
}
]
}
Where as in this sample, results should be deserialized into List<ClassB>.
Some of the field names may show up in different types, but some are not. Functionally they are two different types representing the outputs from two separate API calls, so I'd like to have it deserialize into specific object types as opposed to using dynamic or a monolithic object that contains every possible field.
Currently I'm taking the List<dynamic> and serializing it back into a temporary JSON string, then deserializing it again into the List<ClassA> or whatever. This seems like a bad way to do it, and is cumbersome to work with.
Is there a better way to structure this or to handle the serialization/deserialization? I have full control over both ends so it's not too difficult for me to alter the JSON as well if needed. Also, I know that a particular API call will return JSON that looks like this, while another API call will return JSON that looks like that. Each case should result in a differently typed list
Since you know in advance what type of data is being returned in "results" for each API call, you can make your WorkbenchAPI class generic:
public abstract class WorkbenchAPI
{
protected abstract IReadOnlyCollection<dynamic> GetResults();
public string status { get; set; }
public HttpStatusCode code { get; set; }
public string error { get; set; }
public string guid { get; set; }
public IReadOnlyCollection<dynamic> results => GetResults();
}
public class WorkbenchAPI<T> : WorkbenchAPI where T : class
{
protected override IReadOnlyCollection<dynamic> GetResults() => results;
public new List<T> results { get; set; } = new List<T>();
}
Notes:
I extracted the common properties into an abstract base class to allow them to be accessed by pre-existing non-generic code that does not care about the specific type of result.
I also added a IReadOnlyCollection<dynamic> results to the base class to ease integration with pre-existing code, e.g.:
// Deserialize to the concrete, known type
var root = JsonConvert.DeserializeObject<WorkbenchAPI<ClassA>>(json);
// Access the results in a type-safe manner:
var accounts = root.results.Select(r => r.SamAccountName).ToList();
// Upcast to the base class in code where we don't need to know about the specific result type.
// E.g.: accessing root properties like guid or getting the result count.
WorkbenchAPI baseRoot = root;
var count = baseRoot.results.Count;
var guid = baseRoot.guid;
However, adding access to the results as a non-generic read-only collection of dynamic objects is optional, and could be removed if your legacy code can be rewritten to be generic.
Demo fiddle here: https://dotnetfiddle.net/lbTs1z

How can I deserialize this specific json string?

I am trying to deserialize the following json string using Newtonsoft Json. I am able to get the string successfully, but when I try using JsonConvert.DeserializeObject<ServerList>(response, settings);, the try catch fails.
[
{"endpoint":"127.0.0.1","id":6,"identifiers":["steam:","license:","xbl:","live:","discord:"],"name":"Blurr","ping":160},
{"endpoint":"127.0.0.1","id":7,"identifiers":["steam:","license:","xbl:","live:","discord:"],"name":"Knight","ping":120}
]
I believe my issue is because the players array being unnamed.
I have tried [JsonProperty("")] and [JsonProperty] for the Users var, I have also tried using List and Array instead of IList.
Here is the object. This may be completely wrong, I have tried many ways of doing this.
public class ServerList
{
// I have tried many ways of doing this array/list. This is just the latest way I tried.
[JsonProperty]
public static IList<Player> Users { get; set; }
}
public class Player
{
[JsonProperty("endpoint")]
public static string Endpoint { get; set; }
[JsonProperty("id")]
public static string ServerId { get; set; }
[JsonProperty("identifiers")]
public static IList<string> Identifiers { get; set; }
[JsonProperty("name")]
public static string Name { get; set; }
[JsonProperty("ping")]
public static int Ping { get; set; }
}
I am expecting to get a 'ServerList' object returned with a list of all the players connected to the server.
Ask any questions you need to, I don't often work with json in this format. Thank you in advance!
ERROR: Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.
Simplest way: Your json is an array, so deserialize to an array:
JsonConvert.DeserializeObject<Player[]>(response,settings);
As noted in the comments, properties on the Player should not be static.
If you insist on an object structure similar to what you posted, an object with a Usersproperty, even though it's not present in the JSON, that is also possible, by implementing a custom JSON converter. There's an article with an example of that here: https://www.jerriepelser.com/blog/custom-converters-in-json-net-case-study-1/
HOWEVER; I would recommend sticking to the types present in the json, and perhaps later construct the object that makes sense to the model in your program. This way, what you deserialize are true to the json you are getting, but make no sacrifices on the model you'd like:
var players = JsonConvert.DeserializeObject<Player[]>(response,settings);
var serverList = new ServerList {Users = players};

Cannot deserialze the current JSON array into type

I'm trying to deserialize following JSON data :
{
"bids": [
[
"392031.00000000",
"0.00254444"
],
[
"390000.00000000",
"0.52917503"
],
......
],
"asks": [
[
"392999.00000000",
"1.00000000"
],
[
"393000.00000000",
"0.31572236"
],
.....
]
}
I've looked into similar question such as this one, but I'm not getting close result and also noticed that in that question the structure of JSON is not similar.
My code for deserialization is as below
public class OrderBookElement
{
// I've also tried below commented code
//[JsonProperty(PropertyName = "0")]
//public double price { get; set; }
//[JsonProperty(PropertyName = "1")]
//public double volume { get; set; }
List<double> values;
}
public class OrderBookResponse
{
[JsonProperty(PropertyName = "bids")]
List<OrderBookElement> bids { get; set; }
[JsonProperty(PropertyName = "asks")]
List<OrderBookElement> asks { get; set; }
}
Below is code that I use for deserialization
var ordBook = JsonConvert.DeserializeObject<OrderBookResponse>(jsonResponse);
This gives me error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'RestAPI.OrderBookElement' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
The JSON you've shown would be represented by:
public class OrderBookResponse
{
[JsonProperty("bids")]
public List<List<string>> Bids { get; set; }
[JsonProperty("asks")]
public List<List<string>> Asks { get; set; }
}
The bids and asks properties in the JSON are each just an array of arrays of strings.
I'd suggest deserializing to a model which matches the JSON, then convert that into a more useful model separately. It may be possible to apply attributes to your class to persuade Json.NET to do what you want, but I tend to think that by the time there's a significant discrepancy (not just the property names), it's worth separating the two models out, one for serialization and one for use within the rest of your code.

Serialize subclass with Json.NET

I am trying to use Json.NET to serialize a subclass. The resulting json contains the serialized properties for the superclass but not the properties on the subclass object.
This seems to be related to an issue I found here on SO. But having to write a JsonConverter seems like overkill.
Sample subclass:
public class MySubclass : List<string>
{
public string Name { get; set; }
}
Sample of the serialization:
MySubclass myType = new MySubclass() { Name = "Awesome Subclass" };
myType.Add("I am an item in the list");
string json = JsonConvert.SerializeObject(myType, Newtonsoft.Json.Formatting.Indented);
Resulting json:
[
"I am an item in the list"
]
I expected to result to be more like this:
{
"Name": "Awesome Subclass",
"Items": [
"I am an item in the list"
]
}
Perhaps I am just not using the right configuration when serializing. Anyone have any suggestions?
According the documentation:
.NET lists (types that inherit from IEnumerable) and .NET arrays are
converted to JSON arrays. Because JSON arrays only support a range of
values and not properties, any additional properties and fields
declared on .NET collections are not serialized.
So, don't subclass List<T>, just add a second property.
public class MyClass
{
public List<string> Items { get; set; }
public string Name { get; set; }
public MyClass() { Items = new List<string>(); }
}
Here are my thoughts on this. I would think that your expected results would be more consistent with a class like this:
public class MyClass
{
public string Name { get; set; }
public List<string> Items { get; set; }
}
I would not expect to see an Items element in the serialized result for MySubclass : List<string> since there is no Items property on List nor on MySubclass.
Since your class MySubclass is actually a list of strings, I would guess (and I am just guessing here) that the SerializeObject method is merely iterating through your object and serializing a list of strings.

Categories