Loading JSON file gives serialization error - c#

I have below JSON file,
[
{
"applicationConfig": {
"Name": "Name1",
"Site": "Site1"
},
"pathConfig": {
"SourcePath": "C:\\Temp\\Outgoing1",
"TargetPath": "C:\\Files"
},
"credentialConfig": {
"Username": "test1",
"password": "super1"
}
},
{
"applicationConfig": {
"Name": "Name2",
"Site": "Site2"
},
"pathConfig": {
"SourcePath": "C:\\Temp\\Outgoing2",
"TargetPath": "C:\\Files"
},
"credentialConfig": {
"Username": "test2",
"password": "super2"
}
}
]
And below are C# classes structure,
public class Configurations
{
public List<ApplicationConfig> ApplicationConfigs { get; set; }
public List<PathConfig> PathConfigs { get; set; }
public List<CredentialConfig> CredentialConfigs { get; set; }
}
public class ApplicationConfig
{
public string Name { get; set; }
public string Site { get; set; }
}
public class PathConfig
{
public string SourcePath { get; set; }
public string TargetPath { get; set; }
}
public class CredentialConfig
{
public string Username { get; set; }
public string password { get; set; }
}
Now trying to load JSON and getting below error,
using (var streamReader = new StreamReader(#"./Config.json"))
{
var X = JsonConvert.DeserializeObject<Configurations>(streamReader.ReadToEnd());
}
$exception {"Cannot deserialize the current JSON array (e.g. [1,2,3])
into type 'ConsoleApp8.Configurations' because the type requires a
JSON object (e.g. {\"name\":\"value\"}) to deserialize
correctly.\r\nTo 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 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.\r\nPath '', line 1, position
1."} Newtonsoft.Json.JsonSerializationException
What else I need to serialize?

Your JSON represents an array - although the closing [ should be a ]. But you're trying to serialize it into a single Configurations object. Additionally, you seem to be expecting separate arrays for the application configs, path configs and credential configs - whereas your JSON shows an array of objects, each of which has all three.
I suspect you want:
public class Configuration
{
[JsonProperty("applicationConfig")]
ApplicationConfig ApplicationConfig { get; set; }
[JsonProperty("pathConfig")]
PathConfig PathConfig { get; set; }
[JsonProperty("credentialConfig")]
CredentialConfig CredentialConfig { get; set; }
}
// Other classes as before, although preferably with the password property more conventionally named
Then use:
List<Configuration> configurations =
JsonConvert.DeserializeObject<List<Configuration>>(streamReader.ReadToEnd());
You'll then have a list of configuration objects, each of which will have the three "subconfiguration" parts.

Your JSON class definition is close but not quite. Moroever the last [ must be ]
JSON class definition is created wtih QuickType
public partial class Configuration
{
[JsonProperty("applicationConfig")]
public ApplicationConfig ApplicationConfig { get; set; }
[JsonProperty("pathConfig")]
public PathConfig PathConfig { get; set; }
[JsonProperty("credentialConfig")]
public CredentialConfig CredentialConfig { get; set; }
}
public partial class ApplicationConfig
{
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty("Site")]
public string Site { get; set; }
}
public partial class CredentialConfig
{
[JsonProperty("Username")]
public string Username { get; set; }
[JsonProperty("password")]
public string Password { get; set; }
}
public partial class PathConfig
{
[JsonProperty("SourcePath")]
public string SourcePath { get; set; }
[JsonProperty("TargetPath")]
public string TargetPath { get; set; }
}
Finally you need to serialize with
var config_list = JsonConvert.DeserializeObject<List<Configuration>>(streamReader.ReadToEnd());

I think it is a typo, you are opening the square bracket instead of closing it in the JSON file.
[ {
"applicationConfig": {
"Name": "Name1",
"Site": "Site1"
},
"pathConfig": {
"SourcePath": "C:\Temp\Outgoing1",
"TargetPath": "C:\Files"
},
"credentialConfig": {
"Username": "test1",
"password": "super1"
} }, {
"applicationConfig": {
"Name": "Name2",
"Site": "Site2"
},
"pathConfig": {
"SourcePath": "C:\Temp\Outgoing2",
"TargetPath": "C:\Files"
},
"credentialConfig": {
"Username": "test2",
"password": "super2"
} } [ <-HERE

Related

I can't deserialize the JSON

I'm trying to connect to the PostNL API Timeframes. The problem is that I keep getting the following exception. I think I got my models correctly but I can't seem to find out what's wrong with it.
Exception:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[PostNL.Api.Dtos.TimeFrameHolderDto]' 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.
Path 'Timeframes.Timeframe', line 3, position 16.
at PostNL.Api.Tests.Unit.Tests.Unit.TimeFramesTests.TimeFrameResponseJsonTests.JsonConvertTests(String filePath) in C:\Git\PostNL.Api.Tests.Unit\TimeFramesTests\TimeFrameResponseJsonTests.cs:line 37
If I read the error I need to create some more models with holders and lists like I did as below but I'm still getting this exception. Does anyone know what I'm doing wrong?
requests/1.json file:
{
"Timeframes": {
"Timeframe": [
{
"Date": "22-08-2022",
"Timeframes": {
"TimeframeTimeFrame": [
{
"From": "08:45:00",
"Options": {
"string": "Daytime"
},
"To": "11:15:00"
},
{
"From": "17:30:00",
"Options": {
"string": "Evening"
},
"To": "22:00:00"
}
]
}
},
{
"Date": "23-08-2022",
"Timeframes": {
"TimeframeTimeFrame": [
{
"From": "09:15:00",
"Options": {
"string": "Daytime"
},
"To": "11:45:00"
},
{
"From": "17:30:00",
"Options": {
"string": "Evening"
},
"To": "22:00:00"
}
]
}
}
]
}
}
The deserialization test:
using PostNL.Api.Dtos;
using Newtonsoft.Json;
using NUnit.Framework;
using System;
using System.IO;
namespace PostNL.Api.Tests.Unit.TimeFramesTests
{
[TestFixture]
[Parallelizable(ParallelScope.All)]
internal class TimeFrameResponseJsonTests
{
[Test]
[TestCase("../../../TimeFramesTests/requests/1.json")]
public void JsonConvertTests(string filePath)
{
var path = AppDomain.CurrentDomain.BaseDirectory;
var fullFilePath = Path.Combine(path, filePath);
if (!File.Exists(fullFilePath))
{
Assert.Fail("File does not exists");
return;
}
try
{
var fileContent = File.ReadAllText(filePath);
var json = JsonConvert.DeserializeObject<TimeFrameResponseDto>(fileContent);
}
catch (Exception exception)
{
Assert.Fail(exception.Message);
}
Assert.Pass("Successful convert");
}
}
}
The models:
using Newtonsoft.Json;
using System.Collections.Generic;
namespace PostNL.Api.Dtos
{
internal class TimeFrameDto
{
[JsonProperty("From")]
public string From { get; set; }
[JsonProperty("Options")]
public OptionDto[] Options { get; set; }
[JsonProperty("To")]
public string To { get; set; }
}
internal class TimeFrameTimeFrameHolder
{
[JsonProperty("TimeframeTimeFrame")]
public List<TimeFrameDto> TimeFrameTimeFrame { get; set; }
}
internal class DayTimeFrameDto
{
[JsonProperty("Date")]
public string Date { get; set; }
[JsonProperty("Timeframes")]
public List<TimeFrameTimeFrameHolder> TimeFrameDtos { get; set; }
}
internal class TimeFrameHolderDto
{
[JsonProperty("Timeframe")]
public List<DayTimeFrameDto> TimeFrames { get; set; }
}
internal class TimeFrameResponseDto : PostNLBaseDto
{
[JsonProperty("Timeframes")]
public List<TimeFrameHolderDto> TimeFrames { get; set; }
//[JsonProperty("ReasonNoTimeframes")]
//public List<ReasonNoTimeFrameDto> ReasonNoTimeFrames { get; set; }
}
}
you need one more class - DataTimeframesDto
TimeFramesResponseDTo timeFramesResponseDTo=JsonConvert.DeserializeObject<TimeFramesResponseDTo>(fileContent);
public partial class TimeFramesResponseDTo
{
[JsonProperty("Timeframes")]
public DataTimeframesDto Timeframes { get; set; }
}
public partial class DataTimeframesDto
{
[JsonProperty("Timeframe")]
public List<DayTimeFrameDto> Timeframe { get; set; }
}
UPDATE
The rest of my classes it you still can't use yours
public partial class DayTimeFrameDto
{
[JsonProperty("Date")]
public string Date { get; set; }
[JsonProperty("Timeframes")]
public TimeFrameTimeFrameHolder Timeframes { get; set; }
}
public partial class TimeFrameTimeFrameHolder
{
[JsonProperty("TimeframeTimeFrame")]
public List<TimeframeDTo> TimeFrameTimeFrame{ get; set; }
}
public partial class TimeframeDTo
{
[JsonProperty("From")]
public DateTime From { get; set; }
[JsonProperty("Options")]
public OptionsDto Options { get; set; }
[JsonProperty("To")]
public DateTime To { get; set; }
}
public partial class OptionsDto
{
[JsonProperty("string")]
public string OptionsString { get; set; }
}

How to deserialise this nested json response and save the the array values with multiple Jobjects (in Unity)

I have little to no experience in JSON and I am stuck with a problem. Any help is appreciated.
I want to access specifically the names' values from the additionalInformation array.
JSON Response:
{
"statusCode": 200,
"version": 1,
"jsonData": [
{
"additionalInformation": [
{
"id": "XXX94XXXX9xxXx_xxxXXXX",
"name": "xxxx xxx x xxxxxxxx"
},
{
"id": "0xXXxcXxv5PQqT$6i2zLgV",
"name": "xxx xxxxxxxx"
},
{
"id": "11Krt_our2rPCPqJ_2fKZR",
"name": "xxx xxxxxxxx xx"
},
{
"id": "2jYw4IyBP8KuozM_ej7DGf",
"name": "xxxxxxx 1"
},
{
"id": "3B8O805wL1ufabHMz1Je3v",
"name": "xxxxxxx 2"
},
{
"id": "0FVKUYZkvFaxd_OQUiyPBZ",
"name": "xxxxxxx"
},
{
"id": "3O41QFd0573QQvFco5zUUP",
"name": "Xxxxxxxxx"
}
],
"type": 0
}
],
"errorMessages": [],
"warningMessages": [],
"informationMessages": []
}
Model:
public class CFunctions
{
public int statusCode { get; set; }
public int version { get; set; }
public List<PFunctions>[] jsonData { get; set; }
public List<string> errorMessages { get; set; }
public List<string> warningMessages { get; set; }
public List<string> informationMessages { get; set; }
/*public CFunctions()
{
jsonData = new List<PFunctions>();
}*/
}
[Serializable]
public class PFunctions
{
public List<PAdditionalInfo>[] additionalInformation { get; set; }
public int type { get; set; }
/*public PFunctions()
{
additionalInformation = new List<PAdditionalInfo>();
}*/
}
[Serializable]
public class PAdditionalInfo
{
public Guid id { get; set; }
public string name { get; set; }
}
Deserialisation
var request = UnityWebRequest.Get(baseurl);
var operation = request.SendWebRequest();
var jsonResponse = request.downloadHandler.text;
List<CFunctions>[] PFunctionsList = JsonConvert.DeserializeObject<List<CFunctions>[]>(jsonResponse);
Error:
Cannot deserialize the current JSON object into type 'System.Collections.Generic.List`1[CFunctions][]' because the type requires a JSON array to deserialize correctly.
To fix this error either change the JSON to a JSON array or change the deserialized type so that it is a normal .NET type 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.
Path 'statusCode', line 1, position 14.
UnityEngine.Debug:Log(Object)
What I tried
The error pertains even when I changed List<PAdditionalInfo> to List<PAdditionalInfo>[]
I am not sure how to use JsonObjectAttribute and if it is the best way.
You've declared an array of List<T> in the models, eg List<PAdditionalInfo>[]. The json represents single arrays, not nested. You can fix that by choosing one or the other (I decided to use List<> but array is valid too):
public class PFunctions
{
public List<PAdditionalInfo> additionalInformation { get; set; } // removed []
...
}
public class CFunctions
{
public int statusCode { get; set; }
public int version { get; set; }
public List<PFunctions> jsonData { get; set; } // removed []
...
}
The class you're deserializing to is incorrect. Deserialize to the correct type (which is CFunctions not List<CFunctions>[]):
CFunctions cFunctions = JsonConvert.DeserializeObject<CFunctions>(json);
the most efficient way to get an additional information is this one line code and you only need one class
List<AdditionalInformation> additionalInformation = JObject.Parse(json)
["jsonData"][0]["additionalInformation"].ToObject<List<AdditionalInformation>>();
class
public class AdditionalInformation
{
public string id { get; set; }
public string name { get; set; }
}

How to deserialize from my JSON array to an array of dictionaries whose values are my "Resource" objects in C# .NET using Newtonsoft?

I'm getting the following error when trying to deserliaze my JSON into a Dictionary<string, Resources>[]:
An unhandled exception of type
'Newtonsoft.Json.JsonSerializationException' occurred in
Newtonsoft.Json.dll
Additional information: Cannot deserialize the current JSON object
(e.g. {"name":"value"}) into type
'System.Collections.Generic.Dictionary`2[System.String,MyProject.Resource][]'
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.
My Program.Main():
public class Program
{
public static void Main(string[] Args)
{
var options = new Options()
{
Option1 = "foo",
Option2 = "bar",
Resources = JsonConvert.DeserializeObject<Dictionary<string, Resource>[]>(resources.json)
};
}
}
My resources.json:
{
"global": [
{
"title": "global1",
"url": "~/global1"
},
{
"title": "global2",
"url": "~/global2"
}
],
"ACC": [
{
"title": "acc1",
"url": "~/acc1/"
},
{
"title": "acc2",
"url": "~/acc2/"
}
],
"ECC": [
{
"title": "ecc1",
"url": "~/ecc1/"
},
{
"title": "ecc2",
"url": "~/ecc2/"
}
],
"ECB": [
{
"title": "ecb1",
"url": "~/ecb1"
}
]
}
My Resource class:
public class Resource
{
public List<string> titles { get; set; }
public List<string> urls { get; set; }
}
My Options class:
public class Options
{
public string Option1 { get; set; }
public string Option2 { get; set; }
public Dictionary<string, Resource>[] Resources { get; set; }
}
Your JSON does not represent an array of dictionaries (Dictionary<string, Resource>[]), it represents a dictionary of arrays (Dictionary<string, Resource[]>). That is why you are getting the error.
Also, your Resource class needs to be defined like this to match the JSON:
public class Resource
{
public string Title { get; set; }
public string Url { get; set; }
}
You can then deserialize like this:
Resources = JsonConvert.DeserializeObject<Dictionary<string, Resource[]>>(resources.json)
See fiddle here: https://dotnetfiddle.net/8s2eQd
Your Json doesn't match up with your class structure.
If you want to keep your class structure your json has to look like this:
{
"global":{
"titles":[
"global1",
"global2"
],
"urls":[
"~/global1",
"~/global2"
]
},
"acc":{
"titles":[
"acc1",
"acc2"
],
"urls":[
"~/acc1",
"~/acc2"
]
},
...
}
If you can't influence your json file (for what ever reason) your class structure has to look like this:
public class Rootobject
{
public Global[] global { get; set; }
public ACC[] ACC { get; set; }
public ECC[] ECC { get; set; }
public ECB[] ECB { get; set; }
}
public class Global
{
public string title { get; set; }
public string url { get; set; }
}
public class ACC
{
public string title { get; set; }
public string url { get; set; }
}
public class ECC
{
public string title { get; set; }
public string url { get; set; }
}
public class ECB
{
public string title { get; set; }
public string url { get; set; }
}
Then you can deserialize it like this:
Resources = JsonConvert.DeserializeObject<Rootobject>(resources.json)
Little note for the next time:
If you are not sure how your class structure has to look like (regarding to a json string), you can copy the json string and go to:
Visual Studio -> Edit -> Paste Special -> Paste JSON as Classes
and Visual Studio will make up the appropriate class structure.

JSON deserialize variable number of properties

I have a JSON class structure like this from a third party API (only the problem part shown):
"template": {
"name": "MovieTemplate",
"ruleName": "Movie Template",
"zones": {
"Products": {
"type": "Record",
"name": "Products",
"content": "www.imagescloudsite.com/blahblah.gif"
"records": [ … ]
},
"URL": {
"type":"DVD",
"name":"Bundle"
"content": "www.imagescloudsite.com/blahblah.gif"
}
}
}
The "zones" property can contain many properties "Products","URL","Superman","Descartes",etc...
But, I do not know which ones and how many will be there, because these are added by our content guys in a special control panel. Newtonsoft Deserializer complains because I have a model like this and it clearly does not capture the zone name like 'Products' and 'URL':
public class Zone
{
public string Type { get; set; }
public string Name { get; set; }
public string Content { get; set; }
}
public class Template
{
public string Name { get; set; }
public string RuleName { get; set; }
public List<Zone> Zones { get; set; }
}
Any ideas on how I can capture the zone names using NewtonSoft?
Thanks.
Turn your Zone property to a dictionary since you don't know the keys in before hand, but do know their content structure.
Like so
public class Template
{
public string Name { get; set; }
public string RuleName { get; set; }
public Dictionary<string,Zone> Zones { get; set; }
}
What if you changed the Template class to the following:
public class Template
{
public string Name { get; set; }
public string RuleName { get; set; }
public Dictionary<string, Zone> Zones { get; set; }
}
You could then access the name via the key of the entry.
Use of dynamic would be a good bet
dynamic d = Newtonsoft.Json.Linq.JObject.Parse("{number:1000, str:'string', array: [1,2,3,4,5,6]}");

Parsing nested JSON objects with JSON.NET

My JSON feed has nested objects like this:
{
"id": 1765116,
"name": "StrozeR",
"birth": "2009-08-12",
"avatar": "http:\/\/static.erepublik.com\/uploads\/avatars\/Citizens\/2009\/08\/12\/f19db99e9baddad73981d214a6e576ef_100x100.jpg",
"online": true,
"alive": true,
"ban": null,
"level": 61,
"experience": 183920,
"strength": 25779.42,
"rank": {
"points": 133687587,
"level": 63,
"image": "http:\/\/www.erepublik.com\/images\/modules\/ranks\/god_of_war_1.png",
"name": "God of War*"
},
"elite_citizen": false,
"national_rank": 6,
"residence": {
"country": {
"id": 81,
"name": "Republic of China (Taiwan)",
"code": "TW"
},
"region": {
"id": 484,
"name": "Hokkaido"
}
}
}
and my object classes are like this:
class Citizen
{
public class Rank
{
public int points { get; set; }
public int level { get; set; }
public string image { get; set; }
public string name { get; set; }
}
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public string avatar { get; set; }
public bool online { get; set; }
public bool alive { get; set; }
public string ban { get; set; }
public string birth { get; set; }
public int level { get; set; }
public int experience { get; set; }
public double strength { get; set; }
public List<Rank> rank { get; set; }
}
}
I try to parse my JSON data with following code
private async void getJSON()
{
var http = new HttpClient();
http.MaxResponseContentBufferSize = Int32.MaxValue;
var response = await http.GetStringAsync(uri);
var rootObject = JsonConvert.DeserializeObject<Citizen.RootObject>(response);
uriTB.Text = rootObject.name;
responseDebug.Text = response;
}
but I get the following error:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[Erepublik.Citizen+Rank]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
I can't even parse the value in the main object. Anyway to fix this? and how can I parse a value inside of a nested object? for example: "points" in "rank"
Like the error message says, your rank property in the .NET class is a List<Rank>, but in your JSON it's just a nested object, not an array. Change it to just a Rank instead of a List<Rank>.
Arrays in JSON (or any Javascript, really) are enclosed in []. The {} characters specify a single object. The CLR type has to roughly match the JSON type in order to deserialize. Object to object, array to array.

Categories