Retrieve JSON object till level 1 - c#

I'm reading data from database and converting it to a JSON object which have multiple collections and multiple levels but I only want to retrieve json till level 1 and no related collections or data. I've used following line of code in C# for that purpose
var json = JsonConvert.SerializeObject(obj, new JsonSerializerSettings() { MaxDepth = 1, ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
Above line is returning following
{
"abc": [
{
"Id": "TEST-06",
"No": 1,
"Code": " ",
"Description": ".....",
"Percentage": null,
"Details": []
}
],
"xyz": {
"Id": "TEST-06",
"No.": 1,
"Date": "2018/07/06",
"Enable": 0,
"Reason": "....."
}
}
I only want the object "abc" but it's also returning xyz.
I searched everywhere and they say use max depth property to serialize json object to specific depth. Can anyone please help with that?

You can get only "abc" object simply by using JObject property:
var jObject = JObject.Parse(YourJSonString);
var abcObject = jObject.First;
Update for Without "abc" Object
Create a class with any name for the JSon main object.
public class AnyClass
{
public string Id { get; set; }
public long No { get; set; }
public string Code { get; set; }
public string Description { get; set; }
public object Percentage { get; set; }
public List<object> Details { get; set; }
public List<object> xyz { get; set; }
}
Deserialize your JSon string with this class type:
var deserializeObject = JsonConvert.DeserializeObject<AnyClass>(jsonString);
Now in deserializeObject, you would have all properties and xyz object.

Related

Download values of list from json file with 2 objects

I want to create simple game and i need to get values from json or change them.
I have 3 classes.
public class Person
{
public string Specjality { get; set; }
public int PWZ { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public List<string> Items { get; set; }
}
public class Monster
{
public string Name { get; set; }
public List<string> Skills { get; set; }
}
public class Root
{
public List<Person> people { get; set; }
public List<Monster> monsters { get; set; }
}
Json file
{
"Person": [
{
"Speciality": "Archer",
"PWZ": 432742,
"Name": "Charlie",
"Surname": "Evans",
"Items": [
"Bow",
"Arrow",
]
},
{
"Speciality": "Soldier",
"PWZ": 432534879,
"Name": "Harry",
"Surname": "Thomas",
"Items": [
"Gun",
"Knife",
]
}
],
"Monster": [
{
"Name": "Papua",
"Skills": [
"Jump",
"SlowWalk",
]
},
{
"Name": "Geot",
"Skills": [
"Run",
"Push",
]
}
]
}
My first problem is how to deserialize it, next how to print chosen values (for examples Skills of first Monster) on the screen and how to change some values (for example change "Jump" from Monster Skills to "Teleport" or change Name of Person). Thanks for all answers.
You're very close. To deserialize update the following:
Update/fix spelling/typo in Person class
public string Speciality { get; set; }
Update Root property names (the names should match the Json):
public class Root
{
public List<Person> Person { get; set; }
public List<Monster> Monster { get; set; }
}
Deserialize to Root class:
var result = JsonSerializer.Deserialize<Root>(json);
Now, there's also an issue with trailing commas in your Json string. I got this error:
The JSON array contains a trailing comma at the end which is not
supported in this mode. Change the reader options.
You can fix the Json string (remove the trailing commas in the arrays), or if you're using System.Text.Json to deserialize you can apply the AllowTrailingCommas option:
var options = new JsonSerializerOptions { AllowTrailingCommas = true };
var result = JsonSerializer.Deserialize<Root>(json, options);
To display the values:
// iterate over Person/Monster collection
foreach (var person in result.Person)
Console.WriteLine($"Name: {person.Name}, Items: {string.Join(", ", person.Items)}");
foreach (var monster in result.Monster)
Console.WriteLine($"Name: {monster.Name}, Skills: {string.Join(", ", monster.Skills)}");
To modify an item you would just modify the Person or Monster instance, then serialize again:
// update name:
result.Person[0].Name = "Alan";
// serialize if you need to:
string json = JsonSerializer.Serialize(result);

How to deserialize a JSON to generic objects and get the appropriate type based on the data structure in the JSON?

I want to get the generic data object returned by these JSON:
{
"data": {
"playlist": {
"id": "37682",
"title": "my_playlist",
"count": 12,
"duration": 9705,
...
}
}
}
But I can also get this:
{
"data": {
"album": {
"id": "372",
"cover": ""
"title": "Longing",
"duration": 7705,
"count": 12,
"artist": "the artist"
...
}
}
}
My generic class that supposed to get the data object returned by the server:
public class GenericResponse<T> : IGenericResponse
{
[JsonProperty("data")]
public T Data { get; set; }
object IResponse.Data => Data;
}
One of the object I want to deserialize to from GenericResponse<T>:
[JsonObject("playlist")]
public class PlaylistObject
{
[JsonProperty("id")]
public string Id;
[JsonProperty("title")]
public string Title;
[JsonProperty("duration")]
public int Duration;
[JsonProperty("count")]
public int Count;
}
The request and deserialization:
GenericResponse result = await myEndpoint
.WithOAuthBearerToken(myBearer)
.Request()
.PostAsync(content)
.ReceiveJson<GenericResponse<T>>();
The data sent by the server is there but the result variable is always null when I deserialize it as GenericResponse<T> where T is either a PlaylistObject or an AlbumObject
Your class stucture isn't quite correct, you are missing a wrapper class around the playlist object, something that has a playlist property. For example:
public class PlaylistWrapper
{
public PlaylistObject Playlist { get; set; }
}
Now you should be able to deserialise directly into GenericResponse<PlaylistWrapper>

How to loop through nested JSON objects in C#?

I am working on a C# project where I need to call an API and parse through the JSON response.
The JSON response:
{
"version": "3.9.1",
"data": {
"obj1": {
"version": "1.0.0",
"id": "obj1",
"name": "Object 1",
"title": "Object 1",
"info": {
"info1": 8,
"info2": 4,
"info3": 3
},
"image": {
"full": "Object1.png",
"w": 64,
"h": 64
},
"tags": [
"Tag1",
"Tag2"
]
},
"obj2": {
"version": "1.0.0",
"id": "obj2",
"name": "Object 2",
"title": "Object 2",
"info": {
"info1": 1,
"info2": 6,
"info3": 7
},
"image": {
"full": "Object2.png",
"w": 64,
"h": 64
},
"tags": [
"Tag1",
"Tag6"
]
},
"obj3": {
"version": "1.0.0",
"id": "obj3",
"name": "Object 3",
"title": "Object 3",
"info": {
"info1": 0,
"info2": 1,
"info3": 2
},
"image": {
"full": "Object3.png",
"w": 64,
"h": 64
},
"tags": [
"Tag7",
"Tag8"
]
}
}
}
With this response, I want to loop through all the objects located inside data. The number of objects inside data isn't always the same; it is possible that there will only be one object or ten objects.
The problem I ran into is that I can't loop through the data property because of the following error:
foreach statement cannot operate on variables of type 'Objects' because 'Objects' does not contain a public instance or extension definition for 'GetEnumerator'
I know why I am getting the error, but I can't find a way of fixing my problem.
My code:
MainWindow.xaml.cs
WebRequest request = WebRequest.Create(path);
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string ReaderJson = reader.ReadToEnd();
var JsonResponse = JsonConvert.DeserializeObject<Response>(ReaderJson);
foreach (var obj in JsonResponse.data)
{
Console.WriteLine(obj.ToString());
}
JsonParser.cs
public class Response
{
public string version { get; set; }
public Objects data { get; set; }
}
public class Objects
{
public string id { get; set; }
public string name { get; set; }
public string title { get; set; }
public Info info { get; set; }
public Images images { get; set; }
}
public class Info
{
public int info1 { get; set; }
public int info2 { get; set; }
public int info3 { get; set; }
}
public class Images
{
public string full { get; set; }
public int w { get; set; }
public int h { get; set; }
}
How can I loop through all the objects inside data without calling them using obj1, obj2, etc.?
The problem here is that your JSON schema defines a dictionary for data, but your data property returns a single instance of your Objects class.
Data Model
What you want is for your Response class to look something like this:
public class Response
{
public string version { get; set; }
public Dictionary<string, Objects> data { get; set; }
}
Everything else should be fine.
Looping Through Data
Given the above, you can now loop through the data dictionary using something like:
foreach (var obj in JsonResponse.data)
{
Console.WriteLine(obj.Key);
}
Note: When looping through a Dictionary<TKey, TValue>, an enumeration of KeyValuePair<TKey, TValue>s will be returned, with your key (i.e., obj1) in the Key property, and your object in the Value property.
Naming Conventions
Obviously, the name Objects doesn't makes sense here, since it represents a single object, not a collection of objects. I'm keeping it Objects for consistency with your code, but you'll want to give it a singular name. I assume that was just left over from you wanting it to represent a collection.

Deserialise JSON array object with nested list in C#

I am trying to deserialise the live chat api json response to access the message id and text by filtering using user_type
JSON response
{{
"events": [
{
"type": "agent_details",
"message_id": 1,
"timestamp": 1532396384,
"user_type": "agent",
"agent": {
"name": "Adam Harris",
"job_title": "Support Agent",
"avatar": "livechat.s3.amazonaws.com/default/avatars/ab5b0666feffd67600206cd519fd77ea.jpg"
}
},
{
"type": "message",
"message_id": 3,
"timestamp": 1532396387,
"user_type": "visitor",
"text": "hi"
}
]
}}
JsonOject Class
class JsonLiveChatEvent
{
public class Rootobject
{
public Event[] events { get; set; }
}
public class Event
{
public string type { get; set; }
public int message_id { get; set; }
public int timestamp { get; set; }
public string user_type { get; set; }
public Agent agent { get; set; }
public string text { get; set; }
}
public class Agent
{
public string name { get; set; }
public string job_title { get; set; }
public string avatar { get; set; }
}
}
JsonConverter
string jsonStr= await Api.Chat.GetPendingMessages(visitorID, licenseID,
var chatEvent = JsonConvert.DeserializeObject<Rootobject>(jsonStr);
The chatEvent object will not let me call chatEvent.events.message_id for example. Any help would be greatly appreciated as this is my first time working with json in c#
There is nothing to do with JSON, you have parsed the JSON data back to Rootobject.
Now you are working with an instance of Rootobject as:
Rootobject chatEvent = JsonConvert.DeserializeObject<Rootobject>(jsonStr);
Event event1 = chatEvent.events[0];
Event event2 = chatEvent.events[1];
Also, consider the answer from Mohammad, because above JSON will throw an exception.
The main problem here is that your json is not valid, there is an extra { in the beginning and an extra } in the end.
Then you could deserialize your json with the types you provided
Your json contains more that one curly brackets so you have to first remove those
so your json look like
{
"events": [
{
"type": "agent_details",
"message_id": 1,
"timestamp": 1532396384,
"user_type": "agent",
"agent": {
"name": "Adam Harris",
"job_title": "Support Agent",
"avatar": "livechat.s3.amazonaws.com/default/avatars/ab5b0666feffd67600206cd519fd77ea.jpg"
}
},
{
"type": "message",
"message_id": 3,
"timestamp": 1532396387,
"user_type": "visitor",
"text": "hi"
}
]
}
After that you have to collect message ids depending upon user_type
So then we create enum for that
public enum UserType
{
agent, visitor
}
then we simply check in events that if user type is matches with any of above enum value.
If your json contains multiple events with multiple user types then collect those into List<int>.
If your json contains only single event of each user type then collect them into string variables.
Rootobject chatEvent = JsonConvert.DeserializeObject<Rootobject>(jsonStr);
List<int> agent_message_ids = new List<int>();
List<int> visitior_message_ids = new List<int>();
//string agent_message_id = string.Empty;
//string visitior_message_id = string.Empty;
foreach (Event e in chatEvent.events)
{
if (e.user_type == UserType.agent.ToString())
{
agent_message_ids.Add(e.message_id);
//agent_message_id = e.message_id;
}
if (e.user_type == UserType.visitor.ToString())
{
visitior_message_ids.Add(e.message_id);
//visitior_message_id = e.message_id;
}
}
We simply take a list of integers that store message ids for particular user_type
Try once may it help you
Result:
agent_message_ids:
visitor_message_ids:

How can I use ReadAsAsync<T> with this data schema?

I am using System.Net.Http.HttpClient, the version currently available in NuGet,
to retrieve data from a service in json format. The data roughly looks like this:
{
"schema": "Listing",
"data": {
"key": "28ba648c-de24-45d4-a7d9-70f810cf5438",
"children": [{
"kind": "type1",
"data": {
"body": "Four score and seven years ago...",
"parent_id": "2qh3l",
"report_count": 0,
"name": "c4j6yeh"
}
}, {
"kind": "type3",
"data": {
"domain": "abc.def.com",
"flagged": true,
"category": "news",
"saved": false,
"id": "t3dz0",
"created": 1335998011.0
}
}]
}
}
I use HttpContentExtensions.ReadAsAsync<T> to de-serialize that json string into an object graph. The type definitions looks roughly like this:
public class Response
{
public String schema { get;set; }
public ListingData data { get;set; }
}
public class ListingData
{
public string key { get;set; }
public List<OneItem> children { get;set; }
}
Here's the problem: I desire the type of the items in children to vary depending on the kind property. If kind is "type1" then I want to de-serialize an object of... let's call it Type1 . If kind is "type3" then I want an object of type Type3.
Right now, I can deserialize a List<Type1> or a List<Type3>, but I don't know how to tell the de-serialization logic to distinguish between the two.
I could merge all the properties of the "type1" data object and the "type3" data object into a single .NET Type. But the number of properties is large enough that this gets messy.
If the name of the property in the JSON (in this case data) were different, I could distinguish using that. If, for example, the data looked like this:
"children": [{
"kind": "type1",
"t1data": { ... }
}, {
"kind": "type3",
"t3data": { ... }
}]
...then I could do something like this in .NET:
public class OneItem
{
public string kind { get;set; }
public Type1 t1data { get;set; }
public Type3 t3data { get;set; }
}
But my data schema doesn't look like that.
Is it possible to choose the type for de-serialization by the content of the data? In other words,
look at the value of one property (in this case, kind) to determine how to de-serialize the content for another property (in this case, data).
Or is it possible to inject a filter or transformer that acts on the JSON before ReadAsAsync tries to deserialize it?
If so, How?
If you're ok w/ doing some pre-processing on your response and you can use Json.NET, you should be able to do what you want.
Given the following classes:
public class Response
{
public string schema
{
get;
set;
}
public ListingData data
{
get;
set;
}
}
public class ListingData
{
public string key
{
get;
set;
}
public List<object> children
{
get;
set;
}
}
public class Type1
{
public string body
{
get;
set;
}
public string parent_id
{
get;
set;
}
public int report_count
{
get;
set;
}
public string name
{
get;
set;
}
}
public class Type3
{
public string domain
{
get;
set;
}
public bool flagged
{
get;
set;
}
public string category
{
get;
set;
}
public bool saved
{
get;
set;
}
public string id
{
get;
set;
}
public double created
{
get;
set;
}
}
This test passes:
[Test]
public void RoundTrip()
{
var response = new Response
{
schema = "Listing",
data = new ListingData
{
key = "28ba648c-de24-45d4-a7d9-70f810cf5438",
children = new List<object>
{
new Type1
{
body = "Four score and seven years ago...",
parent_id = "2qh3l",
report_count = 0,
name = "c4j6yeh"
},
new Type3
{
domain = "abc.def.com",
flagged = true,
category = "news",
saved = false,
id = "t3dz0",
created = 1335998011.0
}
}
}
};
var jsonSerializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
TypeNameHandling = TypeNameHandling.Objects
};
string serializedResponse = JsonConvert.SerializeObject(response, jsonSerializerSettings);
Console.WriteLine(serializedResponse);
var roundTrippedResponse = JsonConvert.DeserializeObject<Response>(serializedResponse, jsonSerializerSettings);
Assert.That(roundTrippedResponse.data.children.First().GetType(), Is.EqualTo(typeof(Type1)));
Assert.That(roundTrippedResponse.data.children.Last().GetType(), Is.EqualTo(typeof(Type3)));
}
The output written to the console is:
{
"$type": "Test.Response, Test",
"schema": "Listing",
"data": {
"$type": "Test.ListingData, Test",
"key": "28ba648c-de24-45d4-a7d9-70f810cf5438",
"children": [
{
"$type": "Test.Type1, Test",
"body": "Four score and seven years ago...",
"parent_id": "2qh3l",
"report_count": 0,
"name": "c4j6yeh"
},
{
"$type": "Test.Type3, Test",
"domain": "abc.def.com",
"flagged": true,
"category": "news",
"saved": false,
"id": "t3dz0",
"created": 1335998011.0
}
]
}
}
So if you can transform your received response to match that of Json.NET's expected format, this will work.
To piece all of this together, you would need to write a custom MediaTypeFormatter and pass it to the ReadAsAsync<>() call.

Categories

Resources