Deserializing nested JSON arrays using RestSharp - c#

I'm trying to deserialize the following JSON response using RestSharp. I have tried various model structures to extract the data to no avail. I keep getting tripped up on the nested arrays.
I do not have control over the service, so I can't change the format.
JSON Format:
[
{
"results": 19,
"statuscode": 200,
},
[
{
"id": 24,
"name": "bob"
},
{
"id": 82,
"name": "alice"
}
]
]
Using this model, I've been able to pull the data from the first object, but that's all. I'm not sure how exactly to read through the array that comes after the object.
public class Info
{
public int results { get; set; }
public int statuscode { get; set; }
}
Example deseralization:
var deserializer = new JsonDeserializer();
var wat = deserializer.Deserialize<List<List<Info>>>(response);
Am I just completely missing something here or are my only options to write a custom deserializer and/or use something like JSON.NET?

The problem is that your JSON array is exceptionally polymorphic: its first element is an object, and its second element is an array of objects. A more natural way to represent this would have been as a JSON object with two named properties -- but that's not what you have been given. Deserializing this directly to a c# POCO with two named properties in a single step with any serializer is going to be tricky since the JSON data model is quite different than your desired data model. Instead, it may be easiest to deserialize to an intermediate representation and convert. Luckily RestSharp has appropriate intermediate classes JsonObject and JsonArray.
Thus, if you want to deserialize to the following classes:
public class Info
{
public int results { get; set; }
public int statuscode { get; set; }
}
public class IdAndName
{
public int id { get; set; }
public string name { get; set; }
}
public class ResponseContent
{
public Info Info { get; set; }
public List<IdAndName> Data { get; set; }
}
You can do:
var array = (JsonArray)SimpleJson.DeserializeObject(response.Content);
var responseContent = (array == null ? (ResponseContent)null : new ResponseContent()
{
Info = array.OfType<JsonObject>().Select(o => SimpleJson.DeserializeObject<Info>(o.ToString())).FirstOrDefault(),
Data = array.OfType<JsonArray>().SelectMany(a => SimpleJson.DeserializeObject<List<IdAndName>>(a.ToString())).ToList()
});

Related

How to deserialize multiple object within an object?

I have the following JSON which I'm trying to deserialize.
"objects": {
"1612": {
"id": 1612
},
"1626": {
"id": 1626
}
}
I'm trying to deserialize this into a list ideally but I haven't had any luck so far.
I've tried the following:
public List<Object> objects { get; set; }
public Dictionary<string, Team> objects { get; set; }
I know that ideally the JSON should be inside an array [], but it isn't.
Thank you in advance.
Your JSON does not contain any collections, so a list/array would not be appropriate.
You should have a parent object with one property objects:
public class RootObject
{
// I dont know what Team is but I assume it has the 'id' property
public Dictionary<string, Team> Objects { get; set; }
}
If you are using Json.NET then the deserialization would be:
var rootObj = JsonConvert.DeserializeObject<RootObject>(someJson);
Fiddle here

How to parse json with different key names and similar objects in each key?

I have this JSON :
{
"response": {
"PEOPLE": {
"PERSON1": {
"name": "jon",
"last": "jony"
},
"PERSON2": {
"name": "mike",
"last": "mikey"
}
}
}
}
How can I parse it to a dictionary which the key will be the PERSONX string?
I'm new to c#, and know that in Java I need to have one class, where internal key will be : "person_name"...
I suggest create a class because it's easier to work and you have full control of it.
public class Response
{
public Dictionary<string,Person> People{ get; set; }
}
public class Person
{
public string Name { get; set; }
public string Last { get; set; }
}
When properties have different names I use Dictionary and then you can use LINQ to access them.
Get value of a dictionary:
var valueOfFirstPeopleElement = People.FirstOrDefault().Value;
This way you have the person class.
In order to parse the json to this class you must deserialize using a json converter.
Response response = JsonConvert.DeserializeObject<Response>(jsonData);
To do the reverse you Serialize instead.
string jsonData = JsonConvert.SerializeObject(response);

Can't deserialize JSON into C# POCO

I can't convert JSON Object into C# class object I've tried many things but the same error pops up:
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type
'System.Collections.Generic.List`1[CoderwallDotNet.Api.Models.Account]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly.
I am using this JSON and tring to get the response in windows 8.1 application.
[
{
"id": 1,
"time": 40,
"srcLong": 35.909124,
"srcLat": 31.973628,
"destLong": 35.898258,
"destLat": 31.985622,
"subSites": [
{
"id": 1,
"name": "location1"
},
{
"id": 2,
"name": "location2"
},
{
"id": 3,
"name": "locaion3"
}
]
}]
and the I tried to read from the JSON using webclient but its not working it can't recognize it so I am using Newtonsoft.Json and I creted these class to get the response.
public class SubSite
{
public int id { get; set; }
public string name { get; set; }
}
public class RootObject
{
public int id { get; set; }
public int time { get; set; }
public double srcLong { get; set; }
public double srcLat { get; set; }
public double destLong { get; set; }
public double destLat { get; set; }
public List<SubSite> subSites { get; set; }
}
var serviceUri = "http://localhost:24728/api/sites";
var client = new HttpClient();
var response = await client.GetAsync(serviceUri);
var datafile = await response.Content.ReadAsStringAsyn();
List<RootObject> data = JsonConvert.DeserializeObject<List<RootObject>>(datafile);
test1234.Text = data.ToString();//i am trying to for eample destlat
but I can't get the value I am getting the response and everything is fine but idk how to put it into object and use it where ever I want. For example, I want to get the value of time and the other but I have problem with List of subsites or get the location inside the subsites or srclong or srclat and here is the project how to get the Json to c# object:
https://onedrive.live.com/?cid=e648f5a0f179f346&id=E648F5A0F179F346%218429&ithint=folder,rar&authkey=!ALKlJdwsb8ER2FA
This works fine:
var data = JsonConvert.DeserializeObject<RootObject>(datafile)
You can deserialize into a dynamic object if you are not too particular about losing intellisense. One advantage to using a dynamic is that you don't have to create classes just to be able to deserialize and also that you don't need to update your class structures if the returned data has changed. As an example you can do this:
dynamic jsonValue = JsonConvert.DeserializeObject(jsonData);
foreach (dynamic rootObject in jsonValue)
{
theData.destLong.Value <-- use it anyway you want, store in a variable, etc.
// to get to each of the subSite in the rootObject
foreach (dynamic subSite in rootObject.subSites)
{
subSite.id.Value <-- returns an int based on your data
subSite.name.Value <-- returns a string based on your data
}
}
// where jsonData constains the json string you posted
The foreaeach is important because the data you posted will result into an array. You can also just do a jsonValue[0] but watch out for errors for null values, which you should be checking anyway starting with the returned json string.

Questioning received JSON structure

I'm currently using a beta API (http://developer.riotgames.com/api/methods) which returns JSON for all the exposed methods.
I've been able to use JSON.NET to deserialize all of these return values so far. However, today I consumed one of their function which returns a JSON that is valid but is in my opinion not correct.
You're probably wondering, why don't you ask it on the beta forum? I have but I haven't received an answer so far and in general this intrigues me.
A snippet of the JSON return:
"1001": {
"name": "Boots of Speed",
"plaintext": "Slightly increases Movement Speed",
"group": "BootsNormal",
"description": "<...
}
The problem I have with this structure is that the ID is used as a "group" without an identifier. I would be able to use this decently if it had
"ItemID" : "1001"
But it doesn't have that. I don't mind manually parsing it but I'd first like to know whether or not this JSON is correct (not just valid).
Do you agree that this is not a clean way of creating a JSON block that contains a list of elements or am I missing something here? So far I haven't seen any comments on the beta forum of this API so I'm really wondering why.
Edit "valid" vs "correct/usable":
I know it's a valid JSON statement. I'm questioning the fact whether this is usable with JSON.NET.
I have the following class definition (with two subclasses):
public class JSONItem
{
[JsonProperty("tags")]
public string[] Tags { get; set; }
[JsonProperty("plaintext")]
public string Plaintext { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("into")]
public string[] Into { get; set; }
[JsonProperty("image")]
public JSONItemImage Image { get; set; }
[JsonProperty("colloq")]
public string Colloq { get; set; }
[JsonProperty("gold")]
public JSONItemGold Gold { get; set; }
}
When giving the above JSON block to to JSONConvert.DeserializeObject(json) it throws an error because "1001" is not mentioned in JSONItem.
How do you handle this so that you can use JSON.NET?
A class like this won't work because you have no names to give the properties:
public class JSONItemWrapper
{
[JsonProperty("")]
public string ID { get; set; }
[JsonProperty("")]
public JSONItem MyProperty { get; set; }
}
Edit: "consistent with other methods"
The other methods return blocks where every property is within {} and has an identifier. The most recently added function have this "primary key outside of {}" style.
It is a valid json and you can use a type like Dictionary<string, SomeObject> to deserialize your json.
string json = #"{
""1001"": {
""name"": ""Boots of Speed"",
""plaintext"": ""Slightly increases Movement Speed"",
""group"": ""BootsNormal"",
""description"": ""desc...""
}
}";
var dict = JsonConvert.DeserializeObject<Dictionary<string, MyObject>>(json);
and accesing an item later on by its key can be fast too.
public class MyObject
{
public string name { get; set; }
public string plaintext { get; set; }
public string group { get; set; }
public string description { get; set; }
}
It's annoying when APIs do things like this (using numbers as property names), but all is not lost. Simply deserialize the JSON using Json.NET and then access each of the items using the indexer operator on the parent object.
EDIT:
I almost never create DTOs when deserializing JSON. It's lots of unnecessary boilerplate in most cases. I prefer deserializing to a dynamic object, but that won't be as effective when dealing with property names that begin with digits.
Here is how I would deserialize your sample message:
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace JsonExample
{
internal class Program
{
private static void Main()
{
const string json = #"
{
'1001': {
'name': 'Boots of Speed',
'plaintext': 'Slightly increases Movement Speed',
'group': 'BootsNormal',
'description': '<...'
}
}";
var jObject = JsonConvert.DeserializeObject<JObject>(json);
var plaintext = jObject["1001"]["plaintext"].Value<string>();
Console.WriteLine(plaintext);
}
}
}
When put into http://JSONLint.com,
{
"1001": {
"name": "Boots of Speed",
"plaintext": "Slightly increases Movement Speed",
"group": "BootsNormal",
"description": "<..."
}
}
Validates as JSON.

Deserializing JSON data to C# using JSON.NET

I'm relatively new to working with C# and JSON data and am seeking guidance. I'm using C# 3.0, with .NET3.5SP1, and JSON.NET 3.5r6.
I have a defined C# class that I need to populate from a JSON structure. However, not every JSON structure for an entry that is retrieved from the web service contains all possible attributes that are defined within the C# class.
I've been being doing what seems to be the wrong, hard way and just picking out each value one by one from the JObject and transforming the string into the desired class property.
JsonSerializer serializer = new JsonSerializer();
var o = (JObject)serializer.Deserialize(myjsondata);
MyAccount.EmployeeID = (string)o["employeeid"][0];
What is the best way to deserialize a JSON structure into the C# class and handling possible missing data from the JSON source?
My class is defined as:
public class MyAccount
{
[JsonProperty(PropertyName = "username")]
public string UserID { get; set; }
[JsonProperty(PropertyName = "givenname")]
public string GivenName { get; set; }
[JsonProperty(PropertyName = "sn")]
public string Surname { get; set; }
[JsonProperty(PropertyName = "passwordexpired")]
public DateTime PasswordExpire { get; set; }
[JsonProperty(PropertyName = "primaryaffiliation")]
public string PrimaryAffiliation { get; set; }
[JsonProperty(PropertyName = "affiliation")]
public string[] Affiliation { get; set; }
[JsonProperty(PropertyName = "affiliationstatus")]
public string AffiliationStatus { get; set; }
[JsonProperty(PropertyName = "affiliationmodifytimestamp")]
public DateTime AffiliationLastModified { get; set; }
[JsonProperty(PropertyName = "employeeid")]
public string EmployeeID { get; set; }
[JsonProperty(PropertyName = "accountstatus")]
public string AccountStatus { get; set; }
[JsonProperty(PropertyName = "accountstatusexpiration")]
public DateTime AccountStatusExpiration { get; set; }
[JsonProperty(PropertyName = "accountstatusexpmaxdate")]
public DateTime AccountStatusExpirationMaxDate { get; set; }
[JsonProperty(PropertyName = "accountstatusmodifytimestamp")]
public DateTime AccountStatusModified { get; set; }
[JsonProperty(PropertyName = "accountstatusexpnotice")]
public string AccountStatusExpNotice { get; set; }
[JsonProperty(PropertyName = "accountstatusmodifiedby")]
public Dictionary<DateTime, string> AccountStatusModifiedBy { get; set; }
[JsonProperty(PropertyName = "entrycreatedate")]
public DateTime EntryCreatedate { get; set; }
[JsonProperty(PropertyName = "entrydeactivationdate")]
public DateTime EntryDeactivationDate { get; set; }
}
And a sample of the JSON to parse is:
{
"givenname": [
"Robert"
],
"passwordexpired": "20091031041550Z",
"accountstatus": [
"active"
],
"accountstatusexpiration": [
"20100612000000Z"
],
"accountstatusexpmaxdate": [
"20110410000000Z"
],
"accountstatusmodifiedby": {
"20100214173242Z": "tdecker",
"20100304003242Z": "jsmith",
"20100324103242Z": "jsmith",
"20100325000005Z": "rjones",
"20100326210634Z": "jsmith",
"20100326211130Z": "jsmith"
},
"accountstatusmodifytimestamp": [
"20100312001213Z"
],
"affiliation": [
"Employee",
"Contractor",
"Staff"
],
"affiliationmodifytimestamp": [
"20100312001213Z"
],
"affiliationstatus": [
"detached"
],
"entrycreatedate": [
"20000922072747Z"
],
"username": [
"rjohnson"
],
"primaryaffiliation": [
"Staff"
],
"employeeid": [
"999777666"
],
"sn": [
"Johnson"
]
}
Use
var rootObject = JsonConvert.DeserializeObject<RootObject>(string json);
Create your classes on JSON 2 C#
Json.NET documentation: Serializing and Deserializing JSON with Json.NET
Have you tried using the generic DeserializeObject method?
JsonConvert.DeserializeObject<MyAccount>(myjsondata);
Any missing fields in the JSON data should simply be left NULL.
UPDATE:
If the JSON string is an array, try this:
var jarray = JsonConvert.DeserializeObject<List<MyAccount>>(myjsondata);
jarray should then be a List<MyAccount>.
ANOTHER UPDATE:
The exception you're getting isn't consistent with an array of objects- I think the serializer is having problems with your Dictionary-typed accountstatusmodifiedby property.
Try excluding the accountstatusmodifiedby property from the serialization and see if that helps. If it does, you may need to represent that property differently.
Documentation: Serializing and Deserializing JSON with Json.NET
You can use:
JsonConvert.PopulateObject(json, obj);
here: json is the json string,obj is the target object. See: example
Note: PopulateObject() will not erase obj's list data, after Populate(), obj's list member will contains its original data and data from json string
Building off of bbant's answer, this is my complete solution for deserializing JSON from a remote URL.
using Newtonsoft.Json;
using System.Net.Http;
namespace Base
{
public class ApiConsumer<T>
{
public T data;
private string url;
public CalendarApiConsumer(string url)
{
this.url = url;
this.data = getItems();
}
private T getItems()
{
T result = default(T);
HttpClient client = new HttpClient();
// This allows for debugging possible JSON issues
var settings = new JsonSerializerSettings
{
Error = (sender, args) =>
{
if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Break();
}
}
};
using (HttpResponseMessage response = client.GetAsync(this.url).Result)
{
if (response.IsSuccessStatusCode)
{
result = JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result, settings);
}
}
return result;
}
}
}
Usage would be like:
ApiConsumer<FeedResult> feed = new ApiConsumer<FeedResult>("http://example.info/feeds/feeds.aspx?alt=json-in-script");
Where FeedResult is the class generated using the Xamasoft JSON Class Generator
Here is a screenshot of the settings I used, allowing for weird property names which the web version could not account for.
I found my I had built my object incorrectly. I used http://json2csharp.com/ to generate me my object class from the JSON. Once I had the correct Oject I was able to cast without issue. Norbit, Noob mistake. Thought I'd add it in case you have the same issue.
You can try checking some of the class generators online for further information. However, I believe some of the answers have been useful. Here's my approach that may be useful.
The following code was made with a dynamic method in mind.
dynObj = (JArray) JsonConvert.DeserializeObject(nvm);
foreach(JObject item in dynObj) {
foreach(JObject trend in item["trends"]) {
Console.WriteLine("{0}-{1}-{2}", trend["query"], trend["name"], trend["url"]);
}
}
This code basically allows you to access members contained in the Json string. Just a different way without the need of the classes. query, trend and url are the objects contained in the Json string.
You can also use this website. Don't trust the classes a 100% but you get the idea.
Assuming your sample data is correct, your givenname, and other entries wrapped in brackets are arrays in JS... you'll want to use List for those data types. and List for say accountstatusexpmaxdate... I think you example has the dates incorrectly formatted though, so uncertain as to what else is incorrect in your example.
This is an old post, but wanted to make note of the issues.

Categories