How to pass JSON string as array - c#

[
{"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.

Related

Trying to get first object out of an json array in C#

I'm trying to get the first object out of a json array in c#. The Array looks something like this:
[
{
"name": "Joe",
"id": 1
},
{
"name": "Melinda"
"id": 2
}
]
I didn't find a suitable way to do this so I'm asking here. I'm using System.Text.JSON. I'm currently using this code:
class Program
{
public static void Main(String[] args)
{
HttpClient client = new HttpClient();
string url = "example.com";
string json = client.GetStringAsync(url).ToString()!;
Sensor sensor = JsonSerializer.Deserialize<Sensor>(json)!;
Console.WriteLine(sensor.id);
}
}
public class Sensor
{
public string? id { get; set; }
}
Now, unsurprisingly, when i run this code, System.Text.Json throws an error, but i cant decipher what exactly caused it (prbl bc im stupid):
inner exception System.Text.Json.JsonReaderException: 'S' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)
at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first)
at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
at System.Text.Json.Utf8JsonReader.Read()
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
Is there an easy way to do this with System.Text.Json or Newtonsoft.Json?
Thx
You should deserialize json string as new List() and then you can find first element of the list using FirstOrDefault() method as follow :
class Sensor
{
public int Id { get; set; }
public string Name { get; set; }
}
public Sensor GetFirstElementOfJsonArray(String data)
{
JsonSerializerOptions options = new JsonSerializerOptions(){
PropertyNameCaseInsensitive = true };
List<Sensor> sensorList=JsonConvert.Deserialize<List<Sensor>>(data,options);
return sensorList.FirstOrDefault();
}
I think , it will the answer of your question
An approach very close to yours:
using System;
using System.Text.Json;
public class Program
{
public static readonly string data = #"[{""name"": ""Joe"",""id"": 1},{""name"": ""Melinda"", ""id"": 2 }]";
public static void Main()
{
// System.Text.Json defaults to case-sensitive property matching,
// so I need to switch this to insesitive, if the model adheres
// to C# naming convention ( Props start with capital letter)
JsonSerializerOptions jso = new JsonSerializerOptions(){ PropertyNameCaseInsensitive = true };
// We are deserializing an Array vv
var sensors = JsonSerializer.Deserialize<Sensor[]>(data, jso);
// I do an output for demonstration purposes.
// You'd want to check for null and size>0 and then use the first element.
foreach( var sensor in sensors )
{
Console.WriteLine($"{sensor.Id:#0} : {sensor.Name}");
}
}
}
public class Sensor
{
public int Id {get; set;}
public string Name {get; set;}
}
See in action: https://dotnetfiddle.net/t7Dkh8
Another Idea would be to incrementally parse, which is beneficial if the array is long and you only need the first element.
See Incremental JSON Parsing in C#
(Needs NewtonSoft, though)
Another remark that I and Jon Skeet already made in comments:
The errormessage you are getting
'S' is an invalid start of a value. LineNumber: 0 ...
hints towards that the received string might not actually be valid json. So you might want to investigate this, too.
You could set a breakpoint and look into the value using the debugger,
just spit it out to a text file or if you have logging, log it.
There are two issues that I see in your question. The first is that the id field in the json is not a string but an integer. So you either need to change your json so that it looks like this:
[
{
"name": "Joe",
"id": 1,
...
or update your Sensor class to look like this:
public class Sensor
{
public int id { get; set; }
public string? name { get; set; }
}
Once you do that though the other issue is that your json is not an object, but an array. so your code needs to look more like this:
HttpClient client = new HttpClient();
string url = "example.com";
string json = client.GetStringAsync(url).ToString()!;
var sensors = JsonSerializer.Deserialize<IEnumerable<Sensor>>(json)!;
Console.WriteLine(sensors.First().id);
So serialize the json into a collection (IEnumerable), then you can query that collection to get whatever data you need. Also, I don't know if that was just representative data, but in your json example above, there is a comma missing after "Melinda" in the json.
you need to deserialise to a class:
public class Sensor {
public int Id { get; set; }
public string Name { get; set; }
}
JsonSerializer.Deserialize<Sensor>(json)

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

Deserializing JSON issue

I need to deserialize just part of a JSON string returned from a server. The 'myData' portion in the JSON string below.
My JSON string is structured as follows.
{
"data": {
"CODE": {
"someData": {
"h": "foo",
"id": "City",
"lat": "11.11111"
},
"feedMe": [
[
{
"myData": {
"item1": "a",
"item2": "b",
"item3": "c"
},
"moreData": {}
}
]
]
}
}
}
In Unity there is the JSONutility.FromJson method
https://docs.unity3d.com/ScriptReference/JsonUtility.FromJson.html
but unsure how I would either
1 pass only the 'myData' portion to this method.
or
2 Deserialize the entire string
An alternativ to using JsonUtility there is good old SimpleJSON which allows you to only access a certain field of your json like e.g.
var N = JSON.Parse(the_JSON_string);
var myData = N["data"]["CODE"]["feedMe"][0][0];
var item2 = myData["item2"].Value;
In general the simplest way to get the needed c# class structure for your json is always using json2csharp and make all classes [Serializable] and remove the {get; set;} in order to use fields instead of properties. Something like this
[Serializable]
public class SomeData
{
public string h;
public string id;
public string lat;
}
[Serializable]
public class CODE
{
public SomeData someData;
public List<List<MyData>> feedMe;
}
[Serializable]
public class MyData
{
public string item1;
public string item2;
public string item3;
}
[Serializable]
public class Data
{
public CODE CODE;
}
[Serializable]
public class RootObject
{
public Data data;
}
Instead of List<T> you can also use T[] if you like. And the class names actually don't matter but the structure and field names have to match.
and then use
var root = JsonUtility.FromJson<RootObject>(THE_JSON_STRING);
var myData = root.data.CODE.feedMe[0][0];
var item2 = myData.item2;
As already comented however there is a nested array in your array .. not sure if this is intended.
well, use one of the powerful json nuget -newtonsoft.json , then in your code you can iterate the values like below
var files = JObject.Parse(YourJSON);
var recList = files.SelectTokens("$..data").ToList();
foreach (JObject obj in recList.Children())
{
foreach (JProperty prop in obj.Children())
{
var key = prop.Name.ToString();
var value = prop.Value.ToString();
//Do your stuffs here
}
}
JsonUtility not work whit json files, this only for save and load basic public variables of some class. Asset Store have many frameworks for parse json. p.s. your json is strange, [] its array and you have feedMe:[[{myData, moreData}]]. One array whene just one object in array... parse confusing.

How can I return my object property name as node name

I am stuck while returning api result, I have a class like
public partial class Sample
{
[JsonProperty("classificator")]
public List<Classificator> Classificator { get; set; }
}
public partial class Classificator
{
[JsonProperty("Value")]
public string Value { get; set; }
[JsonProperty("Description")]
public string Description { get; set; }
}
Let's say GetJson method retrieve our data from the database, there are 2 records and the data like
-- Value - Description
1- A - AXA
2- B - BXA
response = GetJson(); // this method gets data from db
return Content(HttpStatusCode.OK, response);
when I return this, it's like
{
"classificator": [{
"Value": "A",
"Description": "AXA"
}, {
"Value": "B",
"Description": "BXA"
}
]
}
but I would like to see like, I want to see bellowing result;
{
"classificator": [{
"A": "AXA"
}, {
"B" : "BXA"
}
]
}
I would like to ask you maybe someone knows a good practice or document(tutorial) about it.
I solve it by using, Dictionary < string, model >
but I need to return a huge nested field I cant implement this solution for all different nodes.
I solved by using Dictionary< string, object >
I put 2 nested objects inside of an object value. In my case it looked some complex I refactor and try to work through readable dictionary hierarchy.
basically for this example it something like below,
Dictionary<string, object> fooDict = new Dictionary<string, object>();
fooDict.Add("A", "AXA"); // in my case I put 2 nested object to value field
fooDict.Add("B", "BXA");
var serializedObject = JsonConvert.SerializeObject(fooDict);
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"C:\xxx\result.txt", true))
{
file.WriteLine(serializedObject);
}

How should one interpret this JSON structure?

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.

Categories