Deserialise JSON with random key - c#

I am accessing an API which is returning JSon in the format:
{"status":1,"complete":1,"list":{"293352541":{"item_id":"293352541","fave":"0"},"247320106":{"item_id":"247320106","fave":"0"},"291842735":{"item_id":"291842735","fave":"0"} .....
The problem I am having is with the number before the item_id tag. It is breaking any attempt I make at deserialising as I cannot represent this random integer in an object that I deserialise in to.
I would expect this number to be, for example, the word "Item", so that it is key representing the enclosed object, but having this number means I cannot make an object representation of the JSon.
So
public class MyClass
{
public string status { get; set; }
public string complete { get; set; }
public List<MyObject> list { get; set; }
}
public class MyObject
{
public string item_id { get; set; }
public string fave { get; set; }
}
then
var items = new JavaScriptSerializer().Deserialize<MyClass>(jsontext);
dersialises, but items.list is empty.
Also,
dynamic result = JSon.Parse(jsontext);
works, but I cannot deserialise or access the list of items in a nice way.
Is there any way to do this? thanks

Because it doesn't require predefined types to deserialize into, you can do this with json.net (also available with nuget). For instance:
var jObj = JObject.Parse(data);
var sense = jObj["list"]
.Select(x => (JProperty)x)
.Select(p => new {
propName = p.Name,
itemId = p.Value["item_id"],
fave = p.Value["fave"]});

Related

How to search polymorphic JSON objects in c#?

Deserializing the following json
{
"MetaData1": "hello world",
"MetaData2": 2022,
"Data": {
"ObjectA": {
"id": 1,
"name": "steve",
"hobbies": 1
},
"ObjectB": {
"id": 2,
"name": "dave",
"age": 55
}
}
}
into corresponding c# objects
public class ObjectBase
{
public int id { get; set; }
public string name { get; set; }
}
public class ObjectA : ObjectBase
{
public int hobbies { get; set; }
}
public class ObjectB : ObjectBase
{
public int age { get; set; }
}
public class Data
{
public ObjectA ObjectA { get; set; }
public ObjectB ObjectB { get; set; }
}
public class Root
{
public string metaData1 { get; set; }
public int metaData2 { get; set; }
public Data Data { get; set; }
}
using
Root object = JsonConvert.DeserializeObject<Root>(json);
How could I search the id properties of the object properties of Root.Data for a matching int and return the corresponding name property.
It would also be useful to be able to create List<ObjectBase> so that other LINQ operations could be performed on these objects.
i think what i am ultimately after here is to end up with List<ObjectBase>.
This can be achieved easily with System.Text.Json (or Newtonsoft).
The most natural representation (IMO) given your Json structure would be to deserialize into a Dictionary<string, ObjectBase>. Then you could convert the dictionary to a List<ObjectBase>. You need a class to match the Data element in your (updated) Json:
// 'root' class to represent the 'Data' element
public class Root
{
public string MetaData1 { get; set; }
public int MetaData2 { get; set; }
public Dictionary<string, ObjectBase> Data { get; set; }
}
// Dictionary<string, ObjectBase>
var model = JsonSerializer.Deserialize<Root>(json);
foreach (var key in model.Data.Keys)
// do something with model.Data[key].id/name
// convert to List<ObjectBase>
var list = new List<ObjectBase>(model.Data.Values);
Expanding on Lasse V. Karlsen's comment, you could instead add all properties to a single class and deserialize into a Dictionary<string, SingleClass>:
public class SingleClass
{
public int id { get; set; }
public string name { get; set; }
public int hobbies { get; set; }
public int age { get; set; }
// all other properties...
}
If you choose this method you may want to consider making the additional properties nullable (if you're interested in differentiating between no hobbies property or someone with hobbies = 0, for example).
The methods above will deserialize into either ObjectBase or the SingleClass.
Demo online
Name only lookup
If you need to look up the name property based on the id then you can do that with the following code:
var semiParsed = JsonConvert.DeserializeObject<Dictionary<string, JObject>>(json);
var name = (from node in semiParsed.Values
let id = (int)node.GetValue("id")
where id == lookupId
select (string)node.GetValue("name"))
.FirstOrDefault();
Console.WriteLine(name);
First we deserialize the json into a collection
The top most properties' name will be the keys of the Dictionary
The top most properties' object will be treated as JObjects (semi parsed jsons)
Then we perform a Linq to Json query
We iterate through the JObjects and retrieve their id property
GetValue returns a JToken and since we know it is a number, we cast it to int
We perform a filtering based on the lookupId
And we select the name property's value
Finally we need to issue a FirstOrDefault method call because the previous query returns an IEnumerable<string>
Here I have assumed that the the id is unique. If the provided lookupId is not defined inside the json then the result will be null.
Wrapping object lookup
If you need to perform a look up for the wrapping object then you need to use Json.NET Schema as well:
var generator = new JSchemaGenerator();
JSchema schemaA = generator.Generate(typeof(ObjectA));
JSchema schemaB = generator.Generate(typeof(ObjectB));
var semiParsed = JsonConvert.DeserializeObject<Dictionary<string, JObject>>(json);
var theNode = (from node in semiParsed.Values
let id = (int)node.GetValue("id")
where id == lookupId
select node)
.FirstOrDefault();
if (theNode == null)
return;
if (theNode.IsValid(schemaA))
{
var objA = theNode.ToObject<ObjectA>();
Console.WriteLine(objA.hobbies);
} else if (theNode.IsValid(schemaB))
{
var objB = theNode.ToObject<ObjectB>();
Console.WriteLine(objB.age);
}
First we generate two json schemas from the class definitions
Then we perform almost the same query the only difference here is the select part
We return here the whole JObject object instead of just its name
Finally perform a schema validation
If the retrieved json matches to schemaA then we can safely convert (ToObject) to ObjectA
We check the json against schemaB as well
the simpliest way would be convert your json to dictionary of JObjects, in this case you don't need any classes at all
var dict = JObject.Parse(json).Properties().ToDictionary(jo => jo.Value["id"],jo=>jo.Value);
var searchId=2;
var name = dict[searchId]["name"]; // dave
or you can deserialize json to list of c# objects
List<ObjectBase> list = JObject.Parse(json).Properties()
.Select(jo => jo.Value.ToObject<ObjectBase>()).ToList();
and use linq to get data
This answer using reflection is poorly optimised as pointed out by serge in a reply to his answer.
foreach (var prop in root.GetType().GetProperties())
{
var obj = prop.GetValue(root);
if ((int) obj.GetType().GetProperty("id").GetValue(obj) == 2)
{
Console.WriteLine(obj.GetType().GetProperty("name").GetValue(obj).ToString());
break;
}
}
Another method that gets List<ObjectBase> using reflection
var objects = root.Data.Objects;
List<ObjectBase> objectList = objects.GetType().GetProperties().ToList<PropertyInfo>().ConvertAll(x => (ObjectBase)x.GetValue(objects));
I am going to leave this answer here incase it helps someone who can't get to this point by desterilisation (maybe their objects weren't crated by desterilisation).

Json.Net Deserializing list of c# objects throwing error

I have a list of objects in below json format. I would like to deserialize using below code. It is throwing unable to convert to object error. I have tried below three options, but didnt help. jsoninput is a IEnumerable<string>converted into json object using ToJson().
Error:
{"Error converting value \"{\"id\":\"11ef2c75-9a6d-4cef-8163-94daad4f8397\",\"name\":\"bracing\",\"lastName\":\"male\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false,\"userType\":0,\"profilePrivacy\":1,\"chatPrivacy\":1,\"callPrivacy\":0}\" to type 'Api.Models.UserInfo'. Path '[0]', line 1, position 271."}
var requests1 = JsonConvert.DeserializeObject<UsersInfo>(jsoninput);
var requests2 = JsonConvert.DeserializeObject<IEnumerable<UserInfo>>(jsoninput);
var requests3 = JsonConvert.DeserializeObject<List<UserInfo>>(jsoninput);
//Below are my classes,
public class UsersInfo
{
public List<UserInfo> UserInfoList { get; set; }
public UsersInfo()
{
UserInfoList = new List<UserInfo>();
}
}
public class UserInfo
{
public string Id { set; get; }
public string Name { set; get; }
public string LastName { set; get; }
public string ProfilePictureUrl { set; get; }
public string SmallUrl { set; get; }
public string ThumbnailUrl { get; set; }
public string Country { set; get; }
public bool IsInvalid { set; get; }
}
Below is my json object,
["{\"id\":\"11ef2c75-9a6d-4cef-8163-94daad4f8397\",\"name\":\"bracing\",\"lastName\":\"male\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false}","{\"id\":\"318c0885-2720-472c-ba9e-1d1e120bcf65\",\"name\":\"locomotives\",\"lastName\":\"riddles\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false}"]
Looping through individual items in json input and if i deserialize it like below, it works fine. But i want to deserialize the list fully. Note: jsoninput was a IEnumerable<string> before i convert in json object.
foreach (var re in jsoninput)
{
var request0 = JsonConvert.DeserializeObject<UserInfo>(re);
}
Please look at this fiddle: https://dotnetfiddle.net/XpjuL4
This is the code:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
//Below are my classes,
public class UsersInfo
{
public List<UserInfo> UserInfoList { get; set; }
public UsersInfo()
{
UserInfoList = new List<UserInfo>();
}
}
public class UserInfo
{
public string Id { set; get; }
public string Name { set; get; }
public string LastName { set; get; }
public string ProfilePictureUrl { set; get; }
public string SmallUrl { set; get; }
public string ThumbnailUrl { get; set; }
public string Country { set; get; }
public bool IsInvalid { set; get; }
}
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
Option1();
Option2();
}
public static void Option1(){
string json = #"{""UserInfoList"":[
{""id"":""11ef2c75 - 9a6d - 4cef - 8163 - 94daad4f8397"",""name"":""bracing"",""lastName"":""male"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false},
{ ""id"":""318c0885-2720-472c-ba9e-1d1e120bcf65"",""name"":""locomotives"",""lastName"":""riddles"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false}
]}";
var obj = JsonConvert.DeserializeObject<UsersInfo>(json);
obj.UserInfoList.ForEach(e => Console.WriteLine(e.Id));
}
public static void Option2(){
string json = #"[
{""id"":""11ef2c75 - 9a6d - 4cef - 8163 - 94daad4f8397"",""name"":""bracing"",""lastName"":""male"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false},
{ ""id"":""318c0885-2720-472c-ba9e-1d1e120bcf65"",""name"":""locomotives"",""lastName"":""riddles"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false}
]";
var obj = JsonConvert.DeserializeObject<List<UserInfo>>(json);
obj.ForEach(e => Console.WriteLine(e.Id));
}
}
Both work, and are basically very close to what you are doing. You can either serialize it as a list (based on your json, I think that's the closest to your use case, and that's Option 2).
However, put extra attention to the JSON. I had to re-parse your JSON to make it work (https://jsonformatter.org/json-parser is a nice website to do it). For the sake of explaining the example, in C#, # means raw string, and in raw string, quotes are escaped with double quotes "".
I would expect that the business logic generating this JSON is not correct, if the JSON you pasted is the direct result from it.
EDIT
Given the OP's comment:
Thanks Tu.ma for your thoughts. The other method returns
IEnumerable which is nothing but
Dictionary.Where(x => x.Value == null).Select(x =>
x.Key).ToHashSet(). The values in Dictionary are -> Key
is String, Value is UserInfo object serialized. So, in that case i
should deserialize one by one? If not, i should serialize entire list
in one shot? Am i right? – Raj 12 hours ago
The problem is in the way you are generating the list of UsersInfo. The result from Dictionary<string,string>.Where(x => x.Value == null).Select(x =>
x.Key).ToHashSet() is a bunch of strings, not of objects, so you need to serialize them one by one.
If you are worried about the linearity of the approach, you could consider running through it in parallel. Of course, you need to judge if it fits your application.
var userInfoStrings = Dictionary<string,string>.Where(x => x.Value == null).Select(x => x.Key).ToHashSet();
var UserInfoList = userInfoStrings.AsParallel().Select (u => JsonConvert.DeserializeObject<UsersInfo>(u)).ToList();

How to get json data using c#?

string json string = {\"GetMyClassListResult\":{\"MyClassList\":[{\"Id\":1,\"Amount\":\"5,00\"},{\"Id\":2,\"Amount\":\"10,00\"},{\"Id\":3,\"Amount\":\"20,00\"},{\"Id\":4,\"Amount\":\"25,00\"}],\"ReturnValues\":{\"ErrorCode\":1,\"ErrorDescription\":\"Successful\"}}}
How do get "Id":1" and "Amount":"5,00" ?
First, you would need to declare a class as following.
class MyClass
{
[JsonProperty(PropertyName = "Id")]
public int Id { get; set; }
[JsonProperty(PropertyName = "Amount")]
public string Amount { get; set; }
}
and then, you can do the following in your method
var Jsonobj = JObject.Parse(json);
var list = JsonConvert.DeserializeObject<MyClass[]>(Jsonobj["GetMyClassListResult"]["MyClassList"].ToString()).ToList<MyClass>();
Hope that helps.
Combining the excellent Json.NET package with LINQ you could use:
var result = JObject.Parse(json)["GetMyClassListResult"]["MyClassList"]
.Select(item => new { Id = item["Id"], Amount = item["Amount"] })
.First();
result has the properties Id and Amount corresponding to the first item in the JSON array with values 1 and "5,00".
If instead you wanted an array of all items, just replace First() with ToArray().
So you have straight json and you're trying to convert it into an object to get some meaningful values?
I personally prefer working with classes where I can. I will throw my raw json into a json to C# converter. I like JsonUtils personally. (I have no affiliation, just a great free service.) There are some others out there, but it seems to be the most robust.
If you throw your raw json into there, you get the following classes:
public class MyClassList
{
public int Id { get; set; }
public string Amount { get; set; }
}
public class ReturnValues
{
public int ErrorCode { get; set; }
public string ErrorDescription { get; set; }
}
public class GetMyClassListResult
{
public IList<MyClassList> MyClassList { get; set; }
public ReturnValues ReturnValues { get; set; }
}
public class Example
{
public GetMyClassListResult GetMyClassListResult { get; set; }
}
Alright. Now that we have our models, we can deserialize the json. The most popular library for manipulating json is Newtonsoft.Json, which is available on NuGet or direct download.
You'll need to add a reference to that dll if you choose to download it; Nuget will auto-reference it when you install it.
At the top of your class file, you'll need to add
using Newtonsoft.Json;
along with your other using statements.
In your method you'll call JsonConvert.Deserialize<List<Example>>(json), which will give you your collection in POCOs.
Since there is only one object in the collection you can call .First() on the collection and then access the two values via the Id and Amount properties. You will need to make sure that System.Linq is in your using statements as well.
Full code:
var json = #"{\"GetMyClassListResult\":{\"MyClassList\":[{\"Id\":1,\"Amount\":\"5,00\"},{\"Id\":2,\"Amount\":\"10,00\"},{\"Id\":3,\"Amount\":\"20,00\"},{\"Id\":4,\"Amount\":\"25,00\"}],\"ReturnValues\":{\"ErrorCode\":1,\"ErrorDescription\":\"Successful\"}}}";
var collection = JsonConvert.Deserialize<List<Example>>(json);
var x = collection.First();
var amount = x.Amount;
var id = x.Amount;
You're then free to manipulate or work with those variables as you see fit. :)
first of all you need a class where you will de-serialize this string to your class object.
you need a class which will contain Id and Amount variable.
after that you can de-serialize this string to the object then you can access any data you want.

Deserialize an inner array to objects using JSON.net

An existing JSON-based web-service returns a fairly messy JSON object, where all the useful data is contained in the elements of an array which is itself the content of a 1-element array. Something like this (I'm anonymising it, hopefully no typos):
{"rows":[[
{"name":"John","time":"2016-03-20 01:00:00","id":"2","code":"1234"},
{"name":"Sam","time":"2016-03-20 01:00:00","id":"24","code":"999"},
{"name":"Paul","time":"2016-03-20 01:00:00","id":"12","code":"6512"}
]]}
Using JSON.net I need to access each of those row sub-elements but I'm not sure how to iterate over this and if I should be deserializing to a concrete type or just reading the raw data from my json object.
The data will be aggregated inside a method so the 'type' of each row is not something that needs to be known outside the method.
rows will always be a 1-element array containing an array of elements as shown.
#Fals's solution should work well, but if you want to do away with the RootObject, you can use Json.Net's LINQ-to-JSON API to parse the JSON and get the data into a simple list of items that is easy to work with.
Assuming you have a class defined for the item data like this:
public class Item
{
public string name { get; set; }
public DateTime time { get; set; }
public string id { get; set; }
public string code { get; set; }
}
Then you can do this to get your list of items:
List<Item> items = JObject.Parse(json)["rows"][0]
.Select(jt => jt.ToObject<Item>())
.ToList();
Fiddle: https://dotnetfiddle.net/FtB3Cu
If you want to avoid declaring any classes at all and instead use an anonymous type, you can change the code to this:
var items = JObject.Parse(json)["rows"][0]
.Select(jt => new
{
name = (string)jt["name"],
time = (DateTime)jt["time"],
id = (string)jt["id"],
code = (string)jt["code"]
})
.ToList();
Fiddle: https://dotnetfiddle.net/0QXUzZ
It's simple, your root object contains a List<List<>>:
Your object should look like:
public class InnerObject
{
public string name { get; set; }
public DateTime time { get; set; }
public string id { get; set; }
public string code { get; set; }
}
public class RootObject
{
public List<List<InnerObject>> rows { get; set; }
}
Then use JSON.NET:
string json = #"{'rows':[[
{'name':'John','time':'2016-03-20 01:00:00','id':'2','code':'1234'},
{'name':'Sam','time':'2016-03-20 01:00:00','id':'24','code':'999'},
{'name':'Paul','time':'2016-03-20 01:00:00','id':'12','code':'6512'}
]]}";
var rootObject = JsonConvert.DeserializeObject<RootObject>(json);
By the way, this site json2csharp can generate the C# class from JSON, makes the life ease :)
EDIT:
You can also use dynamic, and then avoid the parser from the `RootObject:
var rootObject = JsonConvert.DeserializeObject<dynamic>(json);
rootObject.rows[0] <--- should have what you need

Deserialize JSON string into a list for dropdownlist in C#

I have a windows form application and would like to deserialize a JSON string that I'm getting from a web address so that I can get just two values from it, how would I go about doing this?
Below is the code I have to get the JSON string, and if you go to the URL that it's getting, you can also see the JSON string. I want to just get the item name, and current price of it. Which you can see the price under the current key.
private void GrabPrices()
{
using (WebClient webClient = new System.Net.WebClient())
{
WebClient n = new WebClient();
var json = n.DownloadString("http://services.runescape.com/m=itemdb_rs/api/catalogue/detail.json?item=1513");
string valueOriginal = Convert.ToString(json);
Console.WriteLine(json);
}
}
It's also going to be iterating through a SQLite database and getting the same data for multiple items based on the item ID, which I'll be able to do myself.
EDIT I'd like to use JSON.Net if possible, I've been trying to use it and it seems easy enough, but I'm still having trouble.
Okay so first of all you need to know your JSON structure, sample:
[{
name: "Micheal",
age: 20
},
{
name: "Bob",
age: 24
}]
With this information you can derive a C# object
public class Person
{
public string Name {get;set;}
public int Age {get;set;}
}
Now you can use JSON.NET to deserialize your JSON into C#:
var people = JsonConvert.DeserializeObject<List<Person>>(jsonString);
If you look at the original JSON it is an array of objects, to deal with this I have used List<T>.
Key things to remember, you need to have the C# object mirror in properties that of the JSON object. If you don't have a list, then you don't need List<T>.
If your JSON objects have camel casing, and you want this converted to the C# conventions, then use this:
var people = JsonConvert.DeserializeObject<List<Person>>(
jsonString,
new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
First of all you need to create a class structure for the JSON
public class Wrapper
{
public Item item;
}
public class Item
{
public string icon { get; set; }
public string icon_large { get; set; }
public int id { get; set; }
public string type { get; set; }
public string typeIcon { get; set; }
public string name { get; set; }
public string description { get; set; }
public GrandExchange current { get; set; }
public GrandExchange today { get; set; }
public bool members { get; set; }
public GrandExchange day30 { get; set; }
public GrandExchange day90 { get; set; }
public GrandExchange day180 { get; set; }
}
public class GrandExchange
{
public string trend { get; set; }
public string price { get; set; }
}
Then you need to serialize the current item into a Wrapper class
var wrapper = JsonConvert.DeserializeObject<Wrapper>(json);
Then if you want multiple items in a list, you can do so with this code :
// Items to find
int[] itemIds = {1513, 1514, 1515, 1516, 1517};
// Create blank list
List<Item> items = new List<Item>();
foreach (int id in itemIds)
{
var n = new WebClient();
// Get JSON
var json = n.DownloadString(String.Format("http://services.runescape.com/m=itemdb_rs/api/catalogue/detail.json?item={0}", id));
// Parse to Item object
var wrapper = JsonConvert.DeserializeObject<Wrapper>(json);
// Append to list
items.Add(wrapper.item);
}
// Do something with list
It is also worth noting that Jagex limit how many times this API can be called from a certain IP within a time frame, going over that limit will block your IP for a certain amount of time. (Will try and find a reference for this)

Categories