JSON deserializing - c#

I am trying to deserializing JSON file which looks like:
{"dataset":{"id":14686248,
"dataset_code":"EURUSD",
"database_code":"ECB",
"name":"EUR vs USD Foreign Exchange Reference Rate",
"description":"Euro (EUR) vs. US Dollar (USD) reference exchange rate. Foreign exchange reference rates are published by the European Central Bank. Reference rates are usually updated by 3:00pm CET, based on a regular daily concertation procedure between various central banks across Europe and around the world. This procedure normally takes place at 2:15pm CET. Reference rates are mid-market rates, calculated as averages of the buying and selling rate; they do not necessarily reflect actual transaction rates. Euro foreign exchange reference rates are always quoted using the 'certain' method (i.e EUR 1 = X foreign currency units, where X is the published reference rate).",
"refreshed_at":"2016-12-01T23:16:13.829Z",
"newest_available_date":"2016-12-01",
"oldest_available_date":"1999-01-04",
"column_names":["Date","Value"],
"frequency":"daily",
"type":"TimeSeries",
"premium":false,
"limit":null,
"transform":null,
"column_index":null,
"start_date":"1999-01-04",
"end_date":"2016-12-01",
"data":[["2016-12-01",1.0627]
,["2016-11-30",1.0635],
...
}}
Here what i have done:
class request
{
[JsonProperty("dataset")]
public dataset dataset { get; set; }
}
class dataset
{
public int id { get; set; }
public string dataset_code { get; set; }
public string database_code { get; set; }
public string name { get; set; }
public string description { get; set; }
public string refreshed_at { get; set; }
public DateTime newest_available_date { get; set; }
public string[] column_names { get; set; }
public string frequency { get; set; }
public string type { get; set; }
public DateTime oldest_available_date { get; set; }
public bool premium { get; set; }
public string column_index { get; set; }
public DateTime start_date { get; set; }
public DateTime end_date { get; set; }
[JsonProperty("data")]
public List<innerdata> data { get; set; }
}
class Data
{
public List<innerdata> data { get; set; }
}
class innerdata
{
public DateTime date { get; set; }
public double rate { get; set; }
static void Main(string[] args)
{
try
{
using (var client = new HttpClient())
{
string result = client.GetStringAsync(MakeQuery()).Result;
var weatherData = JsonConvert.DeserializeObject<request> (result);
}
}
catch (Exception ex)
{
Console.WriteLine("An error occured: " + ex.Message);
}
}
And it ends with an error :
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
'ApiTest.innerdata' 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 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
'dataset.data[0]', line 1, position 1122.

Try this:
[JsonProperty( "data" )]
public List<List<object>> data { get; set; }
In your json in data, you have an array which has an array inside it. The array inside has a datetime at index 0 and a number with decimal at index 1. In C# you cannot have an array with 2 types (date and number). You can use List<object> instead.

It's to do with data
"data":[["2016-12-01",1.0627] ,["2016-11-30",1.0635],
As it stands this is an array of array's without a key pair. Should be more like the below
"data":[{"date": "2016-12-01","rate":1.0627}
,{"date":"2016-11-30","rate":1.0635}]

Related

Cannot deserialize the current JSON object (e.g. {"name":"value"}

This line is giving me the error
Cannot deserialize the current JSON object (e.g. {"name":"value"})
From other posts I gather I should not be putting this into a list. However This worked fine for me until I added the avgPx field.
How can I get this information into my List properly?
Does my list of type <OrderRecord> need to include all the fields returned by the JSON?
List<OrderRecord> orderRecord_Single = new List<OrderRecord>();//define and set to null
OrderRecord_Single = JsonConvert.DeserializeObject<List<OrderRecord>>(orderString);
This is one case of my jsonstring. It has the brackets on it.
"[{\"orderID\":\"5dcc6560-9672-958d-010b-7d18c9d523ab\",\"account\":1024235,\"symbol\":\"ETHUSD\",\"timestamp\":\"2020-04-26T18:21:05.703Z\",\"clOrdID\":\"\",\"side\":\"Buy\",\"price\":194.95,\"orderQty\":1,\"ordStatus\":\"New\",\"text\":\"ZT\",\"transactTime\":\"2020-04-26T18:21:05.703Z\",\"avgPx\":null}]"
public class OrderRecord
{
[JsonProperty("orderID")]
public string orderID { get; set; }
[JsonProperty("symbol")]
public string symbol { get; set; }
[JsonProperty("side")]
public string side { get; set; }
[JsonProperty("price")]
public string price { get; set; }
[JsonProperty("orderQty")]
public string orderQty { get; set; }
[JsonProperty("ordStatus")]
public string ordStatus { get; set; }
[JsonProperty("transactTime")]
public string transactTime { get; set; }
[JsonProperty("timestamp")]
public string timestamp { get; set; }
[JsonProperty("avgPx")]
public string avgPx { get; set; }
}
The error occurs because you are trying deserializing a JSON object to a JSON array. So you should provide a JSON array as in input. For the given JSON, add brackets [ ] to the first and last of the JSON string for creating valid JSON array:
var jsonString = "[{\"orderID\":\"8d853505-248d-e515-ee17-ddcd24b5fecb\",\"account\":1024235,\"symbol\":\"XBTUSD\",\"timestamp\":\"2020-04-20T18:25:07.601Z\",\"clOrdID\":\"\",\"side\":\"Buy\",\"price\":6885.5,\"orderQty\":8700,\"ordStatus\":\"Filled\",\"text\":\"ZT\",\"transactTime\":\"2020-04-20T18:22:11.135Z\",\"avgPx\":6885.5}]"

Convert JSON string to object C#

I have JSON string results as follows.
In this response Sometimes sizeKey and sizeName properties are returned as a string. But sometimes both properties are returns inside an array as follows
I am using following code to convert it to object
var assets = jObject["assets"].Children().ToList();
foreach (var item in assets)
{
decorationAssets.Add(item.ToObject<AEDecorationAssets>());
}
And my AEDecorationAssets class is as follows.
public class AEDecorationAssets
{
public string Id { get; set; }
public string Url { get; set; }
public string[] Colors { get; set; }
public string FontKey { get; set; }
public string SizeKey { get; set; }
public string ViewKey { get; set; }
public string FontName { get; set; }
public int Rotation { get; set; }
public string SizeName { get; set; }
public string TextValue { get; set; }
public string EntityType { get; set; }
public string LocationCode { get; set; }
public string LocationName { get; set; }
public string TextEffectKey { get; set; }
public string TextEffectName { get; set; }
public string DecorationMethod { get; set; }
public string NumDecorationColors { get; set; }
}
At the time when "sizeKey" is an array, the above code gives an error. How can I resolve this issue? Is there any JSON property we can use to resolve it?
One way you can do it is by making your SizeKey type an object (i.e. public object SizeKey { get; set; }), then you can switch/case on item.ToObject<AEDecorationAssets>().SizeKey.GetType() to figure out how to handle it (i.e. if String do this, if JArray do that), etc.
If a JSON type is sometime an array, and sometimes a string, you can't really map it simply to a .NET type, as there is none that supports this behavior.
So first you need a datatype that can store this, like and string[] or List<string>.
It could be that JsonConvert will solve this automatically, but otherwise you'll need to write a custom ContractResolver or JsonConverter. Here you can detect if the source property is a string or array. If it's an array, you can use the default deserialization. If it is a string, you need to convert it to an array with a single value.
Simply get json result for which you want to create c# object and then you can valid json response from https://jsonlint.com/ and then you can create c# object of any type json response which you want through http://json2csharp.com. And after get c# object of your json response you only need to deserialization of your json response to c# object which you have created. which will return you expected result.

Deserialize Json when name is dynamic

I use this simple API, https://exchangeratesapi.io/ and I test with this uri: https://api.exchangeratesapi.io/history?start_at=2018-01-01&end_at=2018-03-01&symbols=SEK.
I want to deserialize the 'rates' part. Here is one response sample
And here is the code
public class ExchangeRate
{
[JsonProperty(PropertyName = "end_at", Order = 1)]
public DateTime EndAt { get; set; }
[JsonProperty(PropertyName = "start_at", Order = 2)]
public DateTime StartAt { get; set; }
[JsonProperty(PropertyName = "rates", Order = 3)]
public Dictionary<string, Rate> Rates { get; set; }
[JsonProperty(PropertyName = "base", Order = 4)]
public string Base { get; set; }
}
public class Rate
{
[JsonProperty]
public Dictionary<string, double> Fields{ get; set; }
}
or
public class Rate
{
[JsonProperty]
public string CurrencyName { get; set; }
[JsonProperty]
public double CurrencyRate { get; set; }
}
And I deserilize it like this
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<ExchangeRateHistory>(response.Content);
My problem is that that Fields is null. Does anyone have any suggestion?
If your key/value pair are not fixed and data must be configurable then Newtonsoft.json has one feature that to be use here and that is [JsonExtensionData]. Read more
Extension data is now written when an object is serialized. Reading and writing extension data makes it possible to automatically round-trip all JSON without adding every property to the .NET type you’re deserializing to. Only declare the properties you’re interested in and let extension data do the rest.
In your case rates key have value as dynamic data so your Rate class will be
public class Rate
{
[JsonExtensionData]
public Dictionary<string, JToken> Fields { get; set; }
}
And then you can deserialize your response content as
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<ExchangeRate>(response.Content);

How to parse JSON in C#

I have a weird JSON string which needs to be parsed in C#. How do I do it. I tried parsing it as a Dictionary but it failed. Can I somehow create a hashmap?
Dictionary<string, string> values = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
The JSON string is here.
I am getting this data using a API. This is the error that i am receiving.
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Collections.Generic.Dictionary`2[System.String,System.String]' 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 shape of your JSON data won't fit in a Dictionary<string,string> because at its top level, it's not a dictionary. It's an array of objects.
You need to write a custom type (class) that matches the shape of your data, then deserialize to a collection of such types.
So, broadly speaking (with untested code...)
public class SomeType
{
public string notificationId{ get; set; }
//etc
public Dictionary<string,string> recruitersMap{ get; set; }
//etc
}
then
JsonConvert.Deserialize<List<SomeType>>(someJson)
this is because your JSON does not represent a Dictionary<string, string>. recruitersMap and jobsMap are both nested objects or collections, not strings.
you could create a POCO class
public class ApiEndPoint // you will find a better name, I'm sure
{
public string notificationId { get; set; }
public string readFlag { get; set; }
public string importantFlag { get; set; }
public string subject { get; set; }
public string folder { get; set; }
public DateTime creationTime { get; set; }
public int notificationCount { get; set; }
public string jobId { get; set; }
public Dictionary<string, string> recruitersMap { get; set; }
public Dictionary<string, string> jobsMap { get; set; }
}
and deserialize the json into a object of that class like this:
JsonConvert.DeserializeObject<List<ApiEndPoint>>(yourJsonString);
What I see is that the JSON you have pointed out has a regular structure and you should create a wrapping model for it see example below or play with it in https://dotnetfiddle.net/TGWTNC.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Newtonsoft.Json;
public class Program
{
public static void Main(string[] args)
{
var webClient = new WebClient();
var json = webClient.DownloadString("https://gist.githubusercontent.com/maskaravivek/33aa0d6556bbb9ecb77a/raw/b815daa55719a754eef5117321e2c0c5621c6a18/gistfile1.txt");
var notifications = JsonConvert.DeserializeObject<Notification[]>(json);
Console.WriteLine(notifications.Count());
Console.ReadLine();
}
}
//adjust the data types according to your needs
public class Notification
{
public string notificationId { get; set; }
public string readFlag { get; set; }
public string importantFlag { get; set; }
public string subject { get; set; }
public string folder { get; set; }
public string creationTime { get; set; }
public string notificationCount { get; set; }
public string jobId { get; set; }
public Dictionary<string, string> recruitersMap { get; set; }
public Dictionary<string, string> jobsMap { get; set; }
}

Can't deserialize json football data

I want to create an Windows Forms application that uses data from football-data.org. This is my first time I'm working with restful/JSON and I'm stuck.
When I try to get all of the leagues that football-data.org provides this is the response you get from the football-data.org api : response
I use the following code to get all of the data correct:(lbResultBox is a listbox)
private void btAllLeagues_Click(object sender, EventArgs e)
{
lbResultBox.Items.Clear();
List<Leagues> LL = GetLeagues("soccerseasons");
foreach (var item in LL)
{
lbResultBox.Items.Add(item.caption);
}
}
public static List<Leagues> GetLeagues(string endurl)
{
var syncClient = new WebClient();
var content = syncClient.DownloadString(baseurl + endurl);
return JsonConvert.DeserializeObject<List<Leagues>>(content);
}
public class Leagues
{
public IDictionary<string,LeagueLinks> _links { get; set; }
public string caption { get; set; }
public string league { get; set; }
public string year { get; set; }
public string numberOfTeams { get; set; }
public string numberOfGames { get; set; }
public string lastUpdated { get; set; }
}
public class LeagueLinks
{
public string href { get; set; }
}
This works.
But when I try to get all the teams from a league this is the response i get from the api. I use this code:
private void btAllTeams_Click(object sender, EventArgs e)
{
List<LeagueTeams> LT = GetLeagueTeams("soccerseasons/" + id + "/teams");
}
public static List<LeagueTeams> GetLeagueTeams(string endurl)
{
var syncClient = new WebClient();
var content = syncClient.DownloadString(baseurl + endurl);
return JsonConvert.DeserializeObject<List<LeagueTeams>>(content);
}
public class LeagueTeams
{
public IDictionary<string, LeagueLinks> _links { get; set; }
public string count { get; set; }
public IDictionary<string, LeagueTeam> teams { get; set; }
}
public class LeagueTeam
{
public IDictionary<string, TeamLinks> _links { get; set; }
public string name { get; set; }
public string code { get; set; }
public string shortName { get; set; }
public string squadMarketValue { get; set; }
public string crestUrl { get; set; }
}
public class TeamLinks
{
public string href { get; set; }
}
But i get the following error:
An unhandled exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
Additional information: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type System.Collections.Generic.IDictionary`2[System.String,FootballTestApplication.LeagueTeam]' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
When i look at what the api give's me for response I can see a difference in how the response begins. With collecting all of the leagues it starts and ends with brackets ([]) but when collecting the teams in a league it doesn't start or end with brackets. When I Add the brackets myself I still get the error. This is how I add the brackets:
return JsonConvert.DeserializeObject<List<LeagueTeams>>("["+content+"]");
What am I doing wrong here?
The problem lies in the fact that the JSON returned is NOT an Array, List, Dictionary or other Enumerable but is instead an object of it's own.
If we take your JSON from that API link and go through it element by element, we learn that your Type is wrong.
You tell the JSON Serializer that the root object is a List<LeagueTeams>, but it is not. It is in fact a single LeagueTeams object.
If we make that modification to the deserializer, and we make a couple modifications to your LeagueTeams class (mostly the fact that you were deserializing the links property wrong), you are all set:
public class LeagueTeams
{
public List<IDictionary<string, string>> _links { get; set; }
public string count { get; set; }
public List<LeagueTeam> teams { get; set; }
}
return JsonConvert.DeserializeObject<LeagueTeams>(content);
I've attached an image of the results.
Additional Notes
Another thing to note: the JSON to C# website (http://json2csharp.com/) does NOT handle this JSON correctly, it in fact generates an object that is almost correct, but not quite. (Though, the generated object will still work properly, it is not an entirely correct mapping of the input JSON.) This is due, in part, to the fault of the generator, but also the website. It attempts to generate a list of a two-property Link element for the root links item, where it instead should have used a list of a dictionary to get correct mappings. (Though, this is a bit befuddling, it is the most correct approach.) Another thing to keep into consideration, yes, it does fine for getting a good start, but generally speaking, proper JSON handling requires more meticulous inspection of the generated objects to guarantee correctness.

Categories