How to parse JSON in C# - 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; }
}

Related

Parsing JSON with dynamic attributes

i have the following JSON i´m requesting from a service with C# using Newtonsoft.Json
[
{"Example1":value1,
"Example2":value1,
"Example3":"value1",
"ExampleList":
{"Example4":"",
"Example5":"value1",
"Example6":"value1",
"Example7":"",
"Example8":"value1"},
"Example9":["value1"],
"Example10":[]
}
]
the problem here are the "ExampleList", "Example9" and "Example10".
"ExampleList" list has no defined number of values. it can be 5, in the next query it can be 20.
I already have a similar request, where I only have the ExampleList without the values ​​above it. I solved this with
Dictionary<string, string>
and it works fine.
My question is, how can I combine these two?
I tried something like this i found here Parsing JSON with dynamic properties
public partial class ExampleClass
{
public int Example1 { get; set; }
public long Example2 { get; set; }
public long Example3 { get; set; }
public ExampleList exampleList { get; set; }
}
public partial class ExampleList
{
Dictionary<string, string> exampleList = new Dictionary<string, string>();
}
Error:
JsonSerializationException: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Models.ExampleClass' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
Edit: Guru Strons solution worked. For Example 9 and 10 I created an array.
public class ExampleClass
{
public int Example1 { get; set; }
public int Example2 { get; set; }
public int Example3 { get; set; }
public Dictionary<string,string> ExampleList { get; set; }
public string[] Example9 { get; set; }
public string[] Example10 { get; set; }
}
var tempAttr = JsonConvert.DeserializeObject<List<ExampleClass>>(response);
If the goal is to deserialize dynamically only the ExampleList - there is no need to introduce class for it, just make property of type Dictionary<string, string>():
public partial class ExampleClass
{
public int Example1 { get; set; }
public long Example2 { get; set; }
public long Example3 { get; set; }
public Dictionary<string, string>() ExampleList { get; set; }
}
There is another problem - it seems that you are trying to deserialize to ExampleClass but your root json is array, so use List<ExampleClass> or another collection type:
JsonConvert.DeserializeObject<List<ExampleClass>>(...);

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.

Can't implement Iterator design pattern after JsonConvert when trying to Deserialize json

I have the following Object that matches the pattern of a JSON object i get from one REST request I send:
public class MyObject
{
public List<string> columns { get; set; }
public List<List<string>> rows { get; set; }
public DisplayValue displayValue { get; set; }
public string currency { get; set; }
public object alert { get; set; }
}
public class DisplayValue
{
public Id DisplayId { get; set; }
}
public class Id
{
public List<string> IdToName { get; set; }
}
this object match to the response I get and the next code is working with the upper implementation of MyObject (I'm using C#'s RestSharp):
var response = client.Execute(request);
result = JsonConvert.DeserializeObject<MyObject>(response.Content);
Now I would like to implement the Iterator design pattern on MyObject since MyObject.rows is the only field I actually use.
So I've changed MyObject class to the following
public class MyObject : IEnumerable<List<string>
{
public List<string> columns { get; set; }
public List<List<string>> rows { get; set; }
public DisplayValue displayValue { get; set; }
public string currency { get; set; }
public object alert { get; set; }
}
public IEnumerator<List<string>> GetEnumerator()
{
foreach (List<string> row in rows)
{
yield return row;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class DisplayValue
{
public Id DisplayId { get; set; }
}
public class Id
{
public List<string> IdToName { get; set; }
}
But when I try to JSONConvert I get the following exception:
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type
'MyObject' 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.
Any idea to why is this happening?
The problem is that Json.NET will try to serialize any POCO that implements IEnumerable<T> for some T as a JSON array rather than a JSON object, as is documented here. Since your JSON is presumably not an array, you receive the exception you are seeing.
Since you don't want your MyObject serialized as an array, you can force Json.NET to (de)serialize it as an object instead by marking it with [JsonObject]:
[JsonObject]
public class MyObject : IEnumerable<List<string>>
{
public List<string> columns { get; set; }
public List<List<string>> rows { get; set; }
public DisplayValue displayValue { get; set; }
public string currency { get; set; }
public object alert { get; set; }
// Implementation of IEnumerable<List<string>>...
}
See JsonObjectAttribute force object serialization.

Deserialize JSON with variable name arrays

I am getting JSON that is being returned from a REST web service for survey responses. It has arrays for the name portion of some of the name value pairs. Additionally the names will be variable depending on the type of questions asked. I'm using JSON.net and trying to deserialize the returned value into some type of object tree that I can walk but can't figure out what structure to use to have it filled in.
I tested the following snippet in LinqPad and fields is always empty. Is there someway to easily read in the variable data or do I have to parse it in code?
void Main() {
string json = #"{
'result_ok':true,
'total_count':'51',
'data':[{
'id':'1',
'status':'Deleted',
'datesubmitted':'2015-01-12 10:43:47',
'[question(3)]':'Red',
'[question(4)]':'Blue',
'[question(18)]':12,
'[variable(\'STANDARD_IP\')]':'127.0.0.1',
'[variable(\'STANDARD_GEOCOUNTRY\')]':'United States'
}]
}";
var responses = JsonConvert.DeserializeObject<RootObject>(json);
responses.Dump();
}
public class RootObject {
public bool result_ok { get; set; }
public string total_count { get; set; }
public List<Response> data { get; set; }
}
public class Response {
public string id { get; set; }
public string status { get; set; }
public string datesubmitted { get; set; }
public List<object> fields = new List<object>();
}
Change the fields property in your Response class to be a Dictionary<string, object>, then mark it with a [JsonExtensionData] attribute like this:
public class Response
{
public string id { get; set; }
public string status { get; set; }
public string datesubmitted { get; set; }
[JsonExtensionData]
public Dictionary<string, object> fields { get; set; }
}
All of the fields with the strange property names will then be placed into the dictionary where you can access them as normal. No extra code is required.
Here is a demo: https://dotnetfiddle.net/1rQUXT

Categories