C# Newtonsoft deserialize JSON array - c#

I'm trying to deserialize an array using Newtonsoft so i can display files from a cloud based server in a listbox but i always end up getting this error no matter what i try:
Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: [. Path '[0].priv', line 4, position 15.'
Thisis an example try to deserialize:
[
{
"code": 200,
"priv": [
{
"file": "file.txt",
"ext": "txt",
"size": "104.86"
},
{
"file": "file2.exe",
"ext": "exe",
"size": "173.74"
},
],
"pub": [
{
"file": "file.txt",
"ext": "txt",
"size": "104.86"
},
{
"file": "file2.exe",
"ext": "exe",
"size": "173.74"
}
]
}
]
I tried using a C# Class like this:
public class ListJson
{
[JsonProperty("pub")]
public List List { get; set; }
}
public class List
{
[JsonProperty("file")]
public string File { get; set; }
[JsonProperty("ext")]
public string Ext { get; set; }
[JsonProperty("size")]
public string Size { get; set; }
}
[JsonProperty("priv")]
public List List { get; set; }
}
public class List
{
[JsonProperty("file")]
public string File { get; set; }
[JsonProperty("ext")]
public string Ext { get; set; }
[JsonProperty("size")]
public string Size { get; set; }
}
And deserialize with:
List<list> fetch = Newtonsoft.Json.JsonConvert.DeserializeObject<List<list>>(json);

The correct C# class structure for your JSON is the following:
public class FileEntry
{
public string file { get; set; }
public string ext { get; set; }
public string size { get; set; }
}
public class FileList
{
public int code { get; set; }
public List<FileEntry> priv { get; set; }
public List<FileEntry> pub { get; set; }
}
Deserializing it in this way:
var fetch = JsonConvert.DeserializeObject<FileList[]>(json);
var fileList = fetch.First(); // here we have a single FileList object
As said in the other answer, creating a class called List doesn't automagically turn it into a collection of objects. You need to declare the types to be deserialized from an array a collection type (e.g. List<T>, T[], etc.).
Small tip: when in doubt, use json2csharp.com to generate strongly typed classes from a json string.

At the moment List has a single List instance called priv, which despite the name: doesn't make it a list. To deserialize a JSON array ("priv": [...]), it needs to an array or list-like type, for example List<T> for some T. Presumably a List<FileThing>, if we assume that FileThing is actually the second type called List (you have 2).

Related

Having issues reading a JSON file in C#

I am a novice in C# and I am having issues reading a JSON file.
The JSON file follows this format:
{
"info": {
"year": 2020,
"version": "1.0",
"description": "fake description",
"date_created": "2020-04-31T20:32:11.8958473Z"
},
"licenses": [
{
"name": "fake name",
"id": 2020
}
],
"images": [
{
"id": 1,
"width": 1280,
"height": 720,
"filename": "filename1.jpeg",
"license": 1
},
{
"id": 2,
"width": 1280,
"height": 720,
"filename": "filename2.jpeg",
"license": 2
},
...
For now I am trying to read the Images section in the JSON file. Here is my class for it:
public class Images
{
[JsonProperty("id")]
public int id { get; set; }
[JsonProperty("width")]
public int width { get; set; }
[JsonProperty("height")]
public int height { get; set; }
[JsonProperty("filename")]
public string filename { get; set; }
[JsonProperty("license")]
public int license { get; set; }
}
public class Image_json
{
[JsonProperty("images")]
public Image Image_json { get; set; }
}
In my main class, I try deserializing it here:
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
namespace C__Playground
{
public class read_json
{
static void Main(string[] args)
{
using (StreamReader r = new StreamReader("COCOExport.json"))
{
string json = r.ReadToEnd();
var test1 = JsonConvert.DeserializeObject<List<Image_json>(json);
}
}
}
}
When I try to run the program, I get this message:
Unhandled exception. Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[C__Playground.Image_jsonJson]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To 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.
I have been following this post here.
I tried using the solution here but it returns empty or I receive a null error. Any insights?
Your problem should be here:
public class Image_json
{
[JsonProperty("images")]
public Image_json Image_json { get; set; }
}
This property is of type Image_json, which is the same as the containing class. You need a collection of Images. Could be an array or a List<Images>.
public class Image_json
{
[JsonProperty("images")]
public List<Images> Image_json { get; set; }
}
BTW, the Images class should be called Image since it holds a single image, not a collection of them.
Please find below code.
Class Images:
public class Images
{
[JsonProperty("id")]
public int id { get; set; }
[JsonProperty("width")]
public int width { get; set; }
[JsonProperty("height")]
public int height { get; set; }
[JsonProperty("filename")]
public string filename { get; set; }
[JsonProperty("license")]
public int license { get; set; }
}
class ImageJson:
public class ImageJson
{
[JsonProperty("images")]
public List<Images> Image_json // We shoild use list of images
{
get; set;
}
}
To test output:
using (StreamReader r = new StreamReader("COCOExport.json"))
{
string json = r.ReadToEnd();
var test1 = JsonConvert.DeserializeObject<ImageJson>(json);
foreach(var output in test1.Image_json)
{
Console.WriteLine(output.id);
Console.WriteLine(output.width);
Console.WriteLine(output.height);
Console.WriteLine(output.filename);
Console.WriteLine(output.license);
}
Console.ReadLine();
}
It is alwasy good practice to use PascalCasing for Properties.
Ex:)
[JsonProperty("id")]
public int Id { get; set; }
Please find solution here. Explained in a video
https://www.youtube.com/watch?v=nHtdReIhvag

C# deserialize multiple JSON collections into a single List<T>

I fetch a collection of collections of the same object from a web api.
I would then like to deserialize the JSON into a single List
The JSON is as follows:
{
"Liverpool": [
{
"playerId": "LIV01",
"name": "Adam Llana",
"position": "Midfielder"
},
{
"playerId": "LIV02",
"name": "Daniel Sturridge",
"position": "Forward"
}
],
"ManchesterUnited": [
{
"playerId": "MNU01",
"name": "Daley Blind",
"position": "Defender"
},
{
"playerId": "MNU02",
"name": "Romelu Lukaku",
"position": "Forward"
}
],
"Arsenal": [
{
"playerId": "ARS01",
"name": "Petr Cech",
"position": "Goalkeeper"
},
{
"playerId": "ARS02",
"name": "Santi Cazorla",
"position": "Midfielder"
}
]
}
What I could like to be able to do is the following as I am not interested in the collection names:
public class Player
{
public string playerId { get; set; }
public string name { get; set; }
public string position { get; set; }
}
List<Player> cards = JsonConvert.DeserializeObject<List<Player>>(jsonContent);
This does not work and produces an error.
Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"})
into type 'System.Collections.Generic.List`1[Player]' because the type
requires a JSON array (e.g. [1,2,3]) to deserialize correctly. To 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.
Is there any way to accomplish this using Newtonsoft.Json?
Because of the variable team names you need to deserialize into Dictionary<string, List<Player>>. From there use SelectMany on the values of the dictionary to get the players
public class Player
{
public string playerId { get; set; }
public string name { get; set; }
public string position { get; set; }
}
var teams = JsonConvert.DeserializeObject<Dictionary<string, List<Player>>>(jsonContent);
List<Player> players = teams.SelectMany(kvp => kvp.Value).ToList();
What you want is to deserialize that object as a dictionary:
var teams = JsonConvert.DeserializeObject<Dictionary<string, List<Player>>>(jsonContent);
The original object isn't an array so it doesn't make sense to deserialize it as an array or a List<T>
Later, if you want only the player list and don't care about the club names, then just use LINQ's SelectMany to flatten the dictionary:
var allPlayers = teams.SelectMany(entry => entry.Value);
If you simply try to create an object for players right now it won't work as the team names are unique. Your class to deserialize should look like this:
public class Teams
{
public Liverpool[] Liverpool { get; set; }
public Manchesterunited[] ManchesterUnited { get; set; }
public Arsenal[] Arsenal { get; set; }
}
public class Liverpool
{
public string playerId { get; set; }
public string name { get; set; }
public string position { get; set; }
}
public class Manchesterunited
{
public string playerId { get; set; }
public string name { get; set; }
public string position { get; set; }
}
public class Arsenal
{
public string playerId { get; set; }
public string name { get; set; }
public string position { get; set; }
}
Now you can straight away deserialize the data to this object.
Teams teams = JsonConvert.DeserializeObject<Teams>(jsonContent);
Their is an option know as Paste Special inside the Edit option in the top File Menu, this option lets you create classes that mimics the properties of a json or xml.

Cannot deserialize the current JSON array when returned value can be either array or single item

I am new to Newtonsoft.Json so please excuse my ignorance - however I am coming up against this issue when trying to Deserialize the following Json to either a c# object or indeed manually.
The Json is
{
"travellerInfo": [
{
"passengerData": {
"travellerInformation": {
"passenger": [
{
"type": "ADT",
"firstName": "MARY MRS"
},
{
"type": "INF",
"firstName": "JOSHUA"
}
],
"traveller": {
"surname": "SMITH",
"quantity": "2"
}
}
}
},
{
"passengerData": {
"travellerInformation": {
"passenger": {
"type": "ADT",
"firstName": "JOHN MR"
},
"traveller": {
"surname": "SMITH",
"quantity": "1"
}
}
}
}
]
}
So as you can see, on the first 'passenger' item, this returns as an Array, however on the second 'passenger' item, it doesn't return as an array, just a single block. I am not in control of the Json being sent to me - it comes from an external system. My C# classes are
public class Passenger
{
public string type { get; set; }
public string firstName { get; set; }
}
public class Traveller
{
public string surname { get; set; }
public string quantity { get; set; }
}
public class TravellerInformation
{
public List<Passenger> passenger { get; set; }
public Traveller traveller { get; set; }
}
public class PassengerData
{
public TravellerInformation travellerInformation { get; set; }
}
public class TravellerInfo
{
public PassengerData passengerData { get; set; }
}
and I call
var example = JsonConvert.DeserializeObject<TravellerInfo>(jsonString);
I am getting the error
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Script1.TravellerInfo' 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.
Path 'travellerInfo', line 57, position 20.
I tried putting a [JsonArray] attribute on the Passenger class to force it to deserialise as an array/list, but same error occured as I think the underlying item is a JProperty instead of a JObject.
So how can I get this to work when the ["passenger"] can come back as both an Array and Single object ?
Cheers in Advance
You can try deserialize it as dynamic and then do some checks to types. Check if it is IEnumerable.
That should do the job.
Try this. Replace List<Passenger> with object passenger in TravellerInformation:
public class Traveller
{
public string surname { get; set; }
public string quantity { get; set; }
}
public class TravellerInformation
{
public object passenger { get; set; }
public Traveller traveller { get; set; }
}
public class PassengerData
{
public TravellerInformation travellerInformation { get; set; }
}
public class TravellerInfo
{
public PassengerData passengerData { get; set; }
}
And call this by passing List<TravellerInfo> instead of TravellerInfo:
var example = JsonConvert.DeserializeObject<List<TravellerInfo>>(jsonString);
Also for these cases you can use this service which automatically creates C# classes from JSON objects, so you don't have to worry about correctness.

deserializing child data collections into ienumerables using JSON.NET

Current I have a project where I'm getting the following sample data ( I want to retrieve only the ids within this json string and stuff them into IEnumerables (explained below):
{
"states": [
{
"id": "AL",
"text": "Alabama (AL)"
},
{
"id": "CO",
"text": "Colorado (CO)"
}
],
"cities": [
{
"id": 71761,
"text": "New Brockton, AL"
},
{
"id": 74988,
"text": "Nathrop, CO"
}
],
"zipCodes": []
}
Notice in the zipCodes, I am getting an empty set, so there is no "id" or "text".
I want to be able to create several IEnumerables from the properties found in this JSON string.
I created an object called Locations that looks like this:
public class Location
{
public IEnumerable<string> States { get; set; }
public IEnumerable<string> ZipCodes { get; set; }
public IEnumerable<decimal> Cities { get; set; }
}
The best way I found to going about this approach is to do each data property one by one and convert, formValues is the json string:
JArray arrStates = (JArray)formValues["states"];
JArray arrCities = (JArray)formValues["cities"];
JArray arrZip = (JArray)formValues["zipCodes"];
and then set the properties in the location object as so:
Location loc = new Location();
loc.States = arrStates.Children().Select(m=>m["id"].Value<string>());
loc.ZipCodes = arrCities.Children().Select(m=>m["id"].Value<string>());
loc.Cities = arrZip.Children().Select(m=>m["id"].Value<string>());
I was wondering if there's a better way of doing this instead of doing all this code maintenance for whenever my json response adds a new property. In fact, I think there's going to be about ten more properties added to the json string.
I want it to be reduced down to where I could just update the Location object, and have the json automatically map to the properties that way. Or atleast a solution that has less maintenance than what I'm doing now.
Also I was wondering if JsonConvert.DeserializeObject would work in my case; but read that JSON.NET treats an IEnumerable as an array, so I'm stumped on this one.
JsonConvert.DeserializeObject would work in your case and it will have less maintenance than what you're doing now.
If you enter your json data to http://json2csharp.com, below is the generated class definition that you can use, I renamed RootObject to Location
public class State
{
public string id { get; set; }
public string text { get; set; }
}
public class City
{
public int id { get; set; }
public string text { get; set; }
}
public class Location
{
public List<State> states { get; set; }
public List<City> cities { get; set; }
public List<object> zipCodes { get; set; }
}
This is how you deserialize the json data into Location
string jsonData = ...; // set the json data here
var location = JsonConvert.DeserializeObject<Location>(jsonData);
You can enumerate through the nested properties to get the ids, for example location.states[0].id will return "AL" and location.cities[1].id will return 74988.
If there's a new property in the json data, let's say it's named countries with id and text like in states, you can create a new Country class
public class Country
{
public string id { get; set; }
public string text { get; set; }
}
and add countries property to Location class
public class Location
{
public List<State> states { get; set; }
public List<City> cities { get; set; }
public List<object> zipCodes { get; set; }
public List<Country> countries { get; set; }
}

nested json c# object deserialization

i have the following json string (jsonString)
[
{
"name":"Fruits",
"references":[
{"stream":{"type":"reference","size":"original",id":"1"}},
],
"arts":[
{"stream":{"type":"art","size":"original","id":"4"}},
{"stream":{"type":"art","size":"medium","id":"9"}},
]
}
]
and the following C# objects
class Item
{
public string Name { get; set; }
public List<Stream> References { get; set; }
public List<Stream> Arts { get; set; }
public Item()
{
}
}
class Stream
{
public string Type { get; set; }
public string Size { get; set; }
public string Id { get; set; }
public Stream()
{
}
}
and the following code
Item item = JsonConvert.DeserializeObject<Item>(jsonString);
when I run the code, it creteas the correct number of references and arts, but each stream has null value (type = null, size = null).
is it posible to do this json.net deserializeobject method or should I manually deserialize ?
EDIT: Okay, ignore the previous answer. The problem is that your arrays (references and arts) contain objects which in turn contain the relevant data. Basically you've got one layer of wrapping too many. For example, this JSON works fine:
[
{
"name":"Fruits",
"references":[
{"Type":"reference","Size":"original","Id":"1"},
],
"arts":[
{"Type":"art","Size":"original","id":"4"},
{"type":"art","size":"medium","id":"9"},
]
}
]
If you can't change the JSON, you may need to introduce a new wrapper type into your object model:
public class StreamWrapper
{
public Stream Stream { get; set; }
}
Then make your Item class have List<StreamWrapper> variables instead of List<Stream>. Does that help?

Categories

Resources