Parse JSON to object - c#

I am working with box api, and trying to parse json object to a class.
This is the json:
{
"type":"folder",
"id":"0",
"sequence_id":null,
"etag":null,
"name":"All Files",
"created_at":null,
"modified_at":null,
"description":"",
"size":9049537,
"path_collection":
{
"total_count":0,"entries":[]
},
"created_by":
{
"type":"user","id":"","name":"","login":""
},
"modified_by":
{
"type":"user",
"id":"111",
"name":"a a",
"login":"a#gmail.com"
},
"trashed_at":null,
"purged_at":null,
"content_created_at":null,
"content_modified_at":null,
"owned_by":
{
"type":"user",
"id":"111",
"name":"a a",
"login":"a#gmail.com"
},
"shared_link":null,
"folder_upload_email":null,
"parent":null,
"item_status":"active",
"item_collection":
{
"total_count":4,
"entries":
[
{
"type":"file",
"id":"22887167395",
"sequence_id":"0",
"etag":"0",
"sha1":"883c99863eefc0f46b3d34915cc4d97a6008fabf",
"name":"13.ppt"
},
{
"type":"file",
"id":"22887169687",
"sequence_id":"0",
"etag":"0",
"sha1":"a345fd68b1c90a3678a3e746e0e5343693d8a022",
"name":"6.docx"
}
],
"offset":0,
"limit":100,
"order":
[
{
"by":"type",
"direction":"ASC"
},
{
"by":"name",
"direction":"ASC"
}
]
}
}
Basically, this is the root folder (in that case) that contains two files:
13.ppt
6.docx
I created a class:
[JsonObject(MemberSerialization.OptIn)]
public class BoxFile
{
[JsonProperty(PropertyName = "type")]
public string Type { get; internal set; }
[JsonProperty(PropertyName = "id")]
public string Id { get; internal set; }
[JsonProperty(PropertyName = "sequence_id")]
public string SequenceId { get; internal set; }
[JsonProperty(PropertyName = "etag")]
public string Etag { get; internal set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; internal set; }
[JsonProperty(PropertyName = "created_at")]
public string CreatedAt { get; internal set; }
[JsonProperty(PropertyName = "modified_at")]
public string ModifiedAt { get; internal set; }
[JsonProperty(PropertyName = "description")]
public string Description { get; internal set; }
[JsonProperty(PropertyName = "size")]
public long Size { get; internal set; }
[JsonProperty(PropertyName = "item_collection")]
public IEnumerable<BoxFile> ItemCollection { get; internal set; }
}
But the "item_collection" part is not working.. it gives me an error..
How do I get a list of subfiles inside "item_collection"?
I use it by:
private T ParseJson<T>(string json) where T : class, new()
{
JObject jobject = JObject.Parse(json);
return JsonConvert.DeserializeObject<T>(jobject.ToString());
}
And:
BoxFile parsed = ParseJson<BoxFile>(json);

You are getting an error because your class structure does not match your JSON. Specifically, in the JSON, the item_collection property is an object, not a list. That JSON object has two properties, total_count and entries, the latter of which contains the actual list of files. To handle this, you need to define another class:
public class ItemCollection
{
[JsonProperty(PropertyName = "entries")]
public IEnumerable<BoxFile> Entries { get; internal set; }
}
and then change the ItemCollection property in your BoxFile class to use this new class:
[JsonProperty(PropertyName = "item_collection")]
public ItemCollection ItemCollection { get; internal set; }
You can then access the list of files like this:
BoxFile parsed = ParseJson<BoxFile>(json);
foreach (BoxFile file in parsed.ItemCollection.Entries)
{
Console.WriteLine(file.Name);
}
Here is a working demo: https://dotnetfiddle.net/DB9Coc
As an aside, you can simplify your ParseJson method to one line. There is no need to parse the JSON to an JObject, turn it back into JSON and then parse it again.
private T ParseJson<T>(string json) where T : class, new()
{
return JsonConvert.DeserializeObject<T>(json);
}

Related

Deserialize JSON using specific properties

I'm trying to deserialize JSON without declaring every property in C#. Here is a cut-down extract of the JSON:
{
"resourceType": "export",
"type": "search",
"total": 50,
"timestamp": "2020-08-02T18:26:06.747+00:00",
"entry": [
{
"url": "test.com/123",
"resource": {
"resourceType": "Slot",
"id": [
"123"
],
"schedule": {
"reference": {
"value": "testvalue"
}
},
"status": "free",
"start": "2020-08-03T08:30+01:00",
"end": "2020-08-03T09:00+01:00"
}
}
]
}
I want to get the values out of entry → resource, id and start.
Any suggestions on the best way to do this?
I've made very good experiences with json2sharp. You can enter your JSON data there and it will generate the classes you need to deserialize the JSON data for you.
public class Reference
{
public string value { get; set; }
}
public class Schedule
{
public Reference reference { get; set; }
}
public class Resource
{
public string resourceType { get; set; }
public List<string> id { get; set; }
public Schedule schedule { get; set; }
public string status { get; set; }
public string start { get; set; }
public string end { get; set; }
}
public class Entry
{
public string url { get; set; }
public Resource resource { get; set; }
}
public class Root
{
public string resourceType { get; set; }
public string type { get; set; }
public int total { get; set; }
public DateTime timestamp { get; set; }
public List<Entry> entry { get; set; }
}
The next step is to choose a framework which will help you to deserialize. Something like Newtonsoft JSON.
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
If you want to get the data without declaring classes, you can use Json.Net's LINQ-to-JSON API (JToken, JObject, etc.). You can use the SelectToken method with a JsonPath expression to get what you are looking for in a couple of lines. Note that .. is the recursive descent operator.
JObject obj = JObject.Parse(json);
List<string> ids = obj.SelectToken("..resource.id").ToObject<List<string>>();
DateTimeOffset start = obj.SelectToken("..resource.start").ToObject<DateTimeOffset>();
Working demo here: https://dotnetfiddle.net/jhBzl4
If it turns out there are actually multiple entries and you want to get the id and start values for all of them, you can use a query like this:
JObject obj = JObject.Parse(json);
var items = obj["entry"]
.Children<JObject>()
.Select(o => new
{
ids = o.SelectToken("resource.id").ToObject<List<string>>(),
start = o.SelectToken("resource.start").ToObject<DateTimeOffset>()
})
.ToList();
Demo: https://dotnetfiddle.net/Qe8NB7
I am not sure why you don't deserialize the lot (even if it's minimally populated) since you have to do the inner classes anyway.
Here is how you could bypass some of the classes (1) by digging into the JObjects
Given
public class Reference
{
public string value { get; set; }
}
public class Schedule
{
public Reference reference { get; set; }
}
public class Resource
{
public string resourceType { get; set; }
public List<string> id { get; set; }
public Schedule schedule { get; set; }
public string status { get; set; }
public string start { get; set; }
public string end { get; set; }
}
public class Entry
{
public string url { get; set; }
public Resource resource { get; set; }
}
You could call
var results = JObject.Parse(input)["entry"]
.Select(x => x.ToObject<Entry>());

Cannot deserialize the JSON array (e.g. [1,2,3]) into type ' ' because type requires JSON object (e.g. {“name”:“value”})

I have JSON returning in the following format:
{
"Items": [
{
"unique_id": "11111111111",
"rages": {
"rage_content": "Hello rage 2",
"date_stamp": "21/07/2017",
"id": 2
}
},
{
"unique_id": "2222222222",
"rages": {
"rage_content": "Hello rage 1",
"date_stamp": "21/07/2017",
"id": 1
}
}
],
"Count": 2,
"ScannedCount": 2
}
And I have the following 2 classes defined:
Items.cs:
namespace ragevent_A0._0._1
{
class Items
{
public String rage_id { get; set; }
public rage rage { get; set; }
}
}
rage.cs:
class rage
{
public String rage_content { get; set; }
public String date_stamp { get; set; }
public int id { get; set; }
}
I am using the following code in order to attempt to deseralize the JSON returned above:
List<Items> data = JsonConvert.DeserializeObject<List<Items>>(json);
However, I am not able to successfully deserialize the data due to the above error. I have tried a few solutions online, however I have not managed to find a solution which works with the format of my returned JSON. I have used a JSON formatter and it is formatted correctly, so that shouldn't be the issue.
Any help would be much appreciated!
For the posted JSON data below should be the model you need (credit: http://json2csharp.com/). There is mismatch between the property name rage_id. You can use JsonProperty attribute
public class Rages
{
public string rage_content { get; set; }
public string date_stamp { get; set; }
public int id { get; set; }
}
public class Item
{
[JsonProperty(Name="rage_id")]
public string unique_id { get; set; }
public Rages rages { get; set; }
}
public class RootObject
{
public List<Item> Items { get; set; }
public int Count { get; set; }
public int ScannedCount { get; set; }
}
Your deserialization should be
var data = JsonConvert.DeserializeObject<RootObject>(json);

Convert JSON array to a c# object collection

I've a JSON like below,
[
{
"document":
{
"createdDate":1476996267864,
"processedDate":1476996267864,
"taxYear":"2015",
"type":"user_document"
}
},
{
"document":
{
"createdDate":1476998303463,
"processedDate":0,
"taxYear":"2015",
"type":"user_document"
}
}
]
I need to convert it into a c# object. My object type is as below-
public class UserDocument
{
[JsonProperty(PropertyName = "type")]
public string type { get; set; }
[JsonProperty(PropertyName = "taxYear")]
public string taxYear { get; set; }
[JsonProperty(PropertyName = "createdDate")]
public string createdDate { get; set; }
[JsonProperty(PropertyName = "processedDate")]
public string processedDate { get; set; }
}
I'm using below code to deserialize the json but all UserDocument properties are null
var test = JsonConvert.DeserializeObject<List<UserDocument>>(jsonString);
Why am I getting all UserDocument properties are null, what's wrong here? I'm not getting any error.
Also can you suggest a good example in getting CouchBase queryresult into a .net object.
Seems your json is not in correct format. If I say your json is like
[
"document":
{
"createdDate":1476996267864,
"processedDate":1476996267864,
"taxYear":"2015",
"type":"user_document"
},
"document":
{
"createdDate":1476998303463,
"processedDate":0,
"taxYear":"2015",
"type":"user_document"
}
]
Then create a model like
public class Document
{
public UserDocument document {get;set;}
}
and change your UserDocument model's createdDate and processedDate properties as double because its like that in your json
public class UserDocument
{
[JsonProperty(PropertyName = "type")]
public string type { get; set; }
[JsonProperty(PropertyName = "taxYear")]
public string taxYear { get; set; }
[JsonProperty(PropertyName = "createdDate")]
public double createdDate { get; set; }
[JsonProperty(PropertyName = "processedDate")]
public double processedDate { get; set; }
}
and then deserialize
var test = JsonConvert.DeserializeObject<List<Document>>(jsonString);
Something like this (using Newtonsoft.Json.Linq):
var documents = JArray.Parse(json).Select(t => t["document"].ToObject<UserDocument>());

Invalid class property declaration for json mapping

I have below json received from mailgun API.
{
"items": [{
"delivery-status": {
"message": null,
"code": 605,
"description": "Not delivering to previously bounced address",
"session-seconds": 0
},
"event": "failed",
"log-level": "error",
"recipient": "test#test.com"
},
{
//some other properties of above types
}]
}
Now I was trying to create a class structure for above json to auto-map the properties after deserializing.
public class test
{
public List<Item> items { get; set; }
}
public class Item
{
public string recipient { get; set; }
public string #event { get; set; }
public DeliveryStatus delivery_status { get; set; }
}
public class DeliveryStatus
{
public string description { get; set; }
}
This is how I deserialize and try to map the properties.
var resp = client.Execute(request);
var json = new JavaScriptSerializer();
var content = json.Deserialize<Dictionary<string, object>>(resp.Content);
test testContent = (test)json.Deserialize(resp.Content, typeof(test));
var eventType = testContent.items[0].#event;
var desc = testContent.items[0].delivery_status.description; //stays null
Now in the above class Item, recipient and #event gets mapped properly and since it was a keyword I was suppose to use preceding # character and it works well. But the delivery-status property from json, does not get mapped with delevery_status property in class DeliveryStatus. I have tried creating it as deliveryStatus or #deliver-status. The earlier on doesn't map again and the later one throws compile time exception. Is there anyway these things can be handled, like declaring a property with - in between? I cannot change response json as it is not getting generated from my end. Hoping for some help.
Update
Changed the class as below referring this answer, but did not help. Its null again.
public class Item
{
public string #event { get; set; }
[JsonProperty(PropertyName = "delivery-status")]
public DeliveryStatus deliveryStatus { get; set; }
}
I am not sure what the issue is at your end, but at least it works if you use this code. Make sure to include a recent version of Newtonsoft.Json in your project and you should be fine.
public class DeliveryStatus
{
public object message { get; set; }
public int code { get; set; }
public string description { get; set; }
[JsonProperty("session-seconds")]
public int session_seconds { get; set; }
}
public class Item
{
[JsonProperty("delivery-status")]
public DeliveryStatus delivery_status { get; set; }
public string #event { get; set; }
[JsonProperty("log-level")]
public string log_level { get; set; }
public string recipient { get; set; }
}
public class RootObject
{
public List<Item> items { get; set; }
}
public static void Main(string[] args)
{
string json = #"{
""items"": [{
""delivery-status"": {
""message"": null,
""code"": 605,
""description"": ""Not delivering to previously bounced address"",
""session-seconds"": 0
},
""event"": ""failed"",
""log-level"": ""error"",
""recipient"": ""test#test.com""
}]
}";
RootObject r = JsonConvert.DeserializeObject<RootObject>(json);
}

Convert JObject to custome entity - c#

I have the following JSON that is returned from an API call:
{
"Success": true,
"Message": null,
"Nodes": [
{
"Title": "Title 1",
"Link": "http://www.google.com",
"Description": null,
"PubDate": "2014-06-19T13:32:00-07:00"
},
{
"Title": "Title 2",
"Link": "http://www.bing.com",
"Description": null,
"PubDate": "2014-06-26T13:14:00-07:00"
},
]
}
I have the following object to convert the JSON to an custom object
[JsonObject(MemberSerialization.OptIn)]
public class MyApiResponse
{
[JsonProperty(PropertyName = "Success")]
public bool Success { get; set; }
[JsonProperty(PropertyName = "Message")]
public string Message { get; set; }
[JsonProperty(PropertyName = "Nodes")]
public IEnumerable<object> Nodes { get; set; }
}
I am able to execute the following line of code to deserialize to the MyApiResponse object.
MyApiResponse response = JsonConvert.DeserializeObject<MyApiResponse>(json);
I would like to loop through the Nodes property of the MyApiResponse object can serialize them into another object. When I try the following snippet of code it throws an error:
foreach(var item in response.Nodes)
{
MyObject obj = JsonConvert.DeserializeObject<MyObject>(item.ToString());
}
What do I need to do to convert item into my MyObject in the foreach loop?
You just need to define a class to represent a Node, then change the Nodes property in your MyApiResponse class to be a List<Node> (or IEnumerable<Node> if you prefer) instead of an IEnumerable<object>. When you call JsonConvert.DeserializeObject<MyApiResponse>(json), the whole JSON response is deserialized in one go. There should not be a need to deserialize each child item individually.
[JsonObject(MemberSerialization.OptIn)]
public class Node
{
[JsonProperty(PropertyName = "Title")]
public string Title { get; set; }
[JsonProperty(PropertyName = "Link")]
public string Link { get; set; }
[JsonProperty(PropertyName = "Description")]
public string Description { get; set; }
[JsonProperty(PropertyName = "PubDate")]
public DateTime PubDate { get; set; }
}
[JsonObject(MemberSerialization.OptIn)]
public class MyApiResponse
{
[JsonProperty(PropertyName = "Success")]
public bool Success { get; set; }
[JsonProperty(PropertyName = "Message")]
public string Message { get; set; }
[JsonProperty(PropertyName = "Nodes")]
public List<Node> Nodes { get; set; }
}
Then:
MyApiResponse response = JsonConvert.DeserializeObject<MyApiResponse>(json);
foreach (Node node in response.Nodes)
{
Console.WriteLine(node.Title);
}

Categories

Resources