How do I deserialize a tree of objects into a DTO? - c#

I am attempting to deserialize a tree of JSon objects I get back into a DTO. The tree can be up to 4 levels deep, and over 1200 nodes. The code is C# using Newtonsoft.Json for deserialization.
EDIT
The JSon looks like:
[
{
"id": 1095,
"name": "Item1-1",
"children": [
{
"id": 1097,
"name": "Item2-2",
"children": [
{
"id": 18,
"name": "Item3-3",
"children": [
{
"id": 19,
"name": "Item4-4",
"children": [],
"level": 4,
"parentId": 18
},
{
"id": 20,
"name": "Item5-4",
"children": [],
"level": 4,
"parentId": 18
}
],
"level": 3,
"parentId": 1097
}
],
"level": 2,
"parentId": 1095
}
],
"level": 1,
"parentId": null
}
]
My DTO is similar to this:
public class MyDTO
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("children")]
public MyDTO[] Children { get; set; }
[JsonProperty("level")]
public int Level { get; set; }
[JsonProperty("parentId")]
public int ParentId { get; set; }
public MyDTO()
{
}
}
I like Brian Rogers' solution in this link, which deserializes the json into objects:
How do I use JSON.NET to deserialize into nested/recursive Dictionary and List?
public static class JsonHelper
{
public static object Deserialize(string json)
{
return ToObject(JToken.Parse(json));
}
private static object ToObject(JToken token)
{
switch (token.Type)
{
case JTokenType.Object:
return token.Children<JProperty>()
.ToDictionary(prop => prop.Name,
prop => ToObject(prop.Value));
case JTokenType.Array:
return token.Select(ToObject).ToList();
default:
return ((JValue)token).Value;
}
}
}
I call the JSonHelper with object obj = JsonHelper.Deserialize(jsonString);
I have been experimenting with converting this code into a method to convert to MyDTO, but I keep running into compiler errors. I have attempted to simply convert the JValue casts with MyDTO and move on to the List with a List.
My goal is to call MyDTO obj = JsonHelp.Deserialize(jsonString) and get the tree of MyDTO objects back. Is it possible to do what I am trying, or should I find a way to cast each object to MyDTO?

First your JSON is missing a brakcet ], then your model needs a nullable parentId. Making a couple simple changes you can then you JsonConvert.DeserializeObject<IEnumerable<MyDTO>>(json).
So your JSON should look like this:
[
{
"id": 1095,
"name": "Item1-1",
"children": [
{
"id": 1097,
"name": "Item2-2",
"children": [
{
"id": 18,
"name": "Item3-3",
"children": [
{
"id": 19,
"name": "Item4-4",
"children": [],
"level": 4,
"parentId": 18
},
{
"id": 20,
"name": "Item5-4",
"children": [],
"level": 4,
"parentId": 18
}
],
"level": 2,
"parentId": 1095
}],
}],
"level": 1,
"parentId": null
}
]
And can be deserialized with this model:
public class MyDTO
{
public int Id { get; set; }
public string Name { get; set; }
public MyDTO[] Children { get; set; }
public int Level { get; set; }
public int? ParentId { get; set; }
}
Using this code:
var dto = JsonConvert.DeserializeObject<IEnumerable<MyDTO>>(json);

Related

Newtonsoft Json - Serialize Deep nested object based on given selected properties

Does Newtonsoft Json have any way to serialize nested objects with only selected properties ?
The model looks like:
class Node
{
int id{ get; set; };
string name{ get; set; };
IList<Node>children{ get; set; };
}
I am creating a tree structure afterwards which looks something like this:
{
"id": 1,
"name": "A",
"children": [
{
"id": 2,
"name": "B",
"children": null
},
{
"id": 3,
"name": "C",
"children": [
{
"id": 10,
"name": "D",
"children": null
}
]
}
]
}
Wrote my own serializer. I passed Children property only .It shows as:
{
"children": [
{
"children": null
},
{
"children": [
{
"children": null
}
]
}
]
}
I want to show all properties and not just children under 1st/root's children.Similar to below.
{
"children": [
{
"id": 2,
"name": "B",
"children": null
},
{
"id": 3,
"name": "C",
"children": [
{
"id": 10,
"name": "D",
"children": null
}
]
}
] }
Also how do I do the same for children.Id where I want to serialize all children.Id of root node,Similar to below
{
"children": [
{
"id": 2
},
{
"id": 3
}
]
}
they have done the same result you want to achieve on this page.
https://weblog.west-wind.com/posts/2012/aug/30/using-jsonnet-for-dynamic-json-parsing
Also, see Here,
https://entityframeworkcore.com/knowledge-base/58283745/self-reference-when-serializing-nested-object
I hope that will be useful.
What do you need your own serializer for? Try the standard one
var jsonDeserialized = JsonConvert.DeserializeObject<Child>(json);
json = JsonConvert.SerializeObject(jsonDeserialized);
Output
{
"id": 1,
"name": "A",
"children": [
{
"id": 2,
"name": "B",
"children": null
},
{
"id": 3,
"name": "C",
"children": [
{
"id": 10,
"name": "D",
"children": null
}
]
}
]
}
Classes
public partial class Child
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("children")]
public List<Child> Children { get; set; }
}
For this
{
"children": [
{
"id": 2,
"name": "B",
"children": null
},
{
"id": 3,
"name": "C",
"children": [
{
"id": 10,
"name": "D",
"children": null
}
]
}
] }
You can use
var jsonDeserialized = JsonConvert.DeserializeObject<Data>(json);
public partial class Data
{
[JsonProperty("children")]
public List<Child> Children { get; set; }
}

Select Token C# Json array

I have the code below and I want to select the child note when I am accessing 'a'.
But the string result is returning null when I select the 'character' node
JObject jObj = (JObject)JsonConvert.DeserializeObject(strJson);
Assert.IsTrue(response.IsSuccessStatusCode.Equals(true));
var a = (JArray)jObj["cast"];
string result = (string)a.SelectToken("character");
This is the JSON response i get from 'a':
{[
{
"character": "Eddard Stark",
"credit_id": "5256c8ad19c2956ff60478a6",
"id": 48,
"name": "Sean Bean",
"profile_path": "/iIxP2IzvcLgr5WaTBD4UfSqaV3q.jpg",
"order": 0
},
{
"character": "Jon Snow",
"credit_id": "5256c8af19c2956ff6047af6",
"id": 239019,
"name": "Kit Harington",
"profile_path": "/dwRmvQUkddCx6Xi7vDrdnQL4SJ0.jpg",
"order": 0
},
{
"character": "Robert Baratheon",
"credit_id": "5256c8ad19c2956ff60478e2",
"id": 13633,
"name": "Mark Addy",
"profile_path": "/tGWYaLPIGvPJiKx9KzTBMITo7uK.jpg",
"order": 1
},
{
"character": "Daenerys Targaryen",
"credit_id": "5256c8af19c2956ff60479f6",
"id": 1223786,
"name": "Emilia Clarke",
"profile_path": "/tB1nE2LJH81f5UMiGhKCSlaqsF1.jpg",
"order": 1
},
{
"character": "Tyrion Lannister",
"credit_id": "5256c8b219c2956ff6047cd8",
"id": 22970,
"name": "Peter Dinklage",
"profile_path": "/xuB7b4GbARu4HN6gq5zMqjGbkwF.jpg",
"order": 2
}
]}
Your JSON seems to be incorrect, you have to remove begin and end curly braces.
Correct JSON:
[{
"character": "Eddard Stark",
"credit_id": "5256c8ad19c2956ff60478a6",
"id": 48,
"name": "Sean Bean",
"profile_path": "/iIxP2IzvcLgr5WaTBD4UfSqaV3q.jpg",
"order": 0
}, {
"character": "Jon Snow",
"credit_id": "5256c8af19c2956ff6047af6",
"id": 239019,
"name": "Kit Harington",
"profile_path": "/dwRmvQUkddCx6Xi7vDrdnQL4SJ0.jpg",
"order": 0
}, {
"character": "Robert Baratheon",
"credit_id": "5256c8ad19c2956ff60478e2",
"id": 13633,
"name": "Mark Addy",
"profile_path": "/tGWYaLPIGvPJiKx9KzTBMITo7uK.jpg",
"order": 1
}, {
"character": "Daenerys Targaryen",
"credit_id": "5256c8af19c2956ff60479f6",
"id": 1223786,
"name": "Emilia Clarke",
"profile_path": "/tB1nE2LJH81f5UMiGhKCSlaqsF1.jpg",
"order": 1
}, {
"character": "Tyrion Lannister",
"credit_id": "5256c8b219c2956ff6047cd8",
"id": 22970,
"name": "Peter Dinklage",
"profile_path": "/xuB7b4GbARu4HN6gq5zMqjGbkwF.jpg",
"order": 2
}]
Equivalent Model class:
public class SampleClass
{
public string character { get; set; }
public string credit_id { get; set; }
public int id { get; set; }
public string name { get; set; }
public string profile_path { get; set; }
public int order { get; set; }
}
Deserialize using the below code:
It will give you List or Array of SampleClass object. You can use foreach loop or LINQ to get all the character field.
List<SampleClass> lsObj = JsonConvert.DeserializeObject<List<SampleClass>>(strJson);
foreach(SampleClass obj in lsObj)
{
string character = obj.character;
}
First you have to create model class You can use http://json2csharp.com/, and deserialize it using Json.NET
use the following namespace
using Newtonsoft.Json;
model class and DeserializeObject method
public class RootObject
{
public string character { get; set; }
public string credit_id { get; set; }
public int id { get; set; }
public string name { get; set; }
public string profile_path { get; set; }
public int order { get; set; }
}
var x =JsonConvert.DeserializeObject<List<RootObject>>(myjsondata);
var character = x[index].character;
Well, you ca just parse your string to JObject directly with JObject.Parse() method or JArray.Parse(). Then you can just iterate through you array and get array objects by index: jsonObj[0]. And if you want get some specific value of that object - use Value<T>() method^ jsonObj[0].Value<string>("character")

Web Api; Entity Framework; Data returns recursive

im facing a problem with probably selfreference Looping:
Model:
public class ProtectedAccount
{
public int Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime Created { get; private set; }
public DateTime? Changed { get; set; }
public bool Disabled { get; set; }
public virtual ICollection<ProtectedAccountMember> Members { get; set; }
public virtual ProtectedAccountType Type { get; set; }
}
public class ProtectedAccountMember
{
public int Id { get; set; }
[StringLength(300)]
public string Name { get; set; }
[Index]
public virtual ProtectedAccount ProtectedAccount { get; set; }
}
Controller:
[ResponseType(typeof(ProtectedAccount))]
[Route("ProtectedAccounts/{id}/Members")]
[HttpGet]
public IHttpActionResult GetProtectedAccountMembers(int id)
{
var protectedAccount = db.ProtectedAccounts.Find(id);
if (protectedAccount == null)
{
return NotFound();
}
return Ok(protectedAccount.Members.ToList());
}
the data wich i receive for an GET seems to Loop recursive through all navigations:
[
{
"ProtectedAccount": {
"Members": [
{
"Id": 2,
"Name": "XXX, XX",
},
{
"Id": 3,
"Name": "XX, XX",
}
],
"Type": null,
"Id": 25,
"ObjectGUID": "76bf65e7-af60-4fe8-b3e1-90afbfd65b65",
"Name": "XXX",
},
"Id": 1,
"Name": "test",
},
{
"ProtectedAccount": {
"Members": [
{
"Id": 1,
"Name": "test",
},
{
"Id": 3,
"Name": "XX, XX",
"SamAccountName": "XX",
"Disabled": false
}
],
"Type": null,
"Id": 25,
"ObjectGUID": "76bf65e7-af60-4fe8-b3e1-90afbfd65b65",
"Name": "XXXX",
},
"Id": 2,
"Name": "XX, XX",
},
{
"ProtectedAccount": {a
"Members": [
{
"Id": 1,
"Name": "test",
"SamAccountName": "XXX",
"Disabled": false
},
{
"Id": 2,
"Name": "XX, XX",
"SamAccountName": "XX",
"Disabled": false
}
],
"Type": null,
"Id": 25,
"ObjectGUID": "76bf65e7-af60-4fe8-b3e1-90afbfd65b65",
"Name": "XXX",
},
"Id": 3,
"Name": "XX, XX",
}
]
There is only one "ProtectedAccount" in the database. DO i have to use DTO to overcome this issue? I tried some configuration via the json formatsettings but didnt get any better results.
From your code, you are only returing the protectedAccount.Members, hence you could do a projection query as below
var results = ctx.ProtectedAccountMembers
.Where(member => member.ProtectedAccount.Id == protectedAccount.Id)
.Select(member => new { member.Id, member.Name }).ToList();

Generate c# classes from json dynamically

I usually use json2csharp to generate json classes to c#. But I do have problem. My json is have dynamic depth like this
{
"kategori": [
{
"id": "1",
"namakategori": "Tips & Trick",
"parent_id": "0",
"children": [
{
"id": "348",
"namakategori": "Fotografi",
"parent_id": "1",
"children": []
},
{
"id": "370",
"namakategori": "Hacking",
"parent_id": "1",
"children": []
}
]
},
{
"id": "12",
"namakategori": "Aplikasi",
"parent_id": "0",
"children": [
{
"id": "13",
"namakategori": "Tools",
"parent_id": "12",
"children": [
{
"id": "14",
"namakategori": "Toolsorder",
"parent_id": "13",
"children":[]
},
]
},
]
},
]
}
So how do I generate json classes dynamically so it can be used for my json? In above example I have 3 depth. But if I go to different page maybe it have 4 or more depth.
You don't need to declere your classes dynamically. This should work:
public class Child
{
public string id { get; set; }
public string namakategori { get; set; }
public string parent_id { get; set; }
public List<Child> children { get; set; } // <-- See this
}
public class RootObj
{
public List<Child> kategori { set; get; }
}
To deserialize I'll use Json.Net
var res = JsonConvert.DeserializeObject<RootObj>(json);
You can always use the Newtonsoft.Json
For Instance,
JObject result = (JObject) JsonConvert.DeserializeObject(yourJsonDataHere);
var katObject = result.Property("kategori").Value;
and so on...
PS: Not sure if Newtonsoft.Json is supported on WP7.

Cannot deserialize the current JSON array

First: I'm new to using JSON, and I used the answers on here to use Json.Net to deserialize data from a Pokemon API into a C# class (Pokemon class). I used http://json2csharp.com to help me define my class and it looks like this:
public class Pokemon
{
public Pokemon(string json)
{
JsonConvert.PopulateObject(json, this, PokeApi.JsonSerializerSettings);
}
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("evolutions")]
public Evolutions evolutions { get; set; }
[JsonProperty("national_id")]
public int national_id { get; set; }
}
with a bunch of other properties like resource_uri, attack stat, etc.
As the answer offered on the aforementioned link said, I used JsonConvert.DeserializeObject(json) like so:
public Pokemon GetPokemon(int nationalId)
{
using (WebClient client = new WebClient())
{
var json = client.DownloadString("http://pokeapi.co/api/v1/pokemon/" + nationalId + "/");
var output = JsonConvert.DeserializeObject<Pokemon>(json);
return output;
}
}
However I keep getting an exception that says "Cannot deserialize the current JSON array (e.g.[1,2,3]) into type 'Evolutions' because the type requires a JSON object..."
I found a lot of other questions asking the same exact thing, but I was confused with the top answers - sometimes the answer was to use JsonProperty, sometimes it was to use JsonConverter, without really an explanation on what all these meant. Do I need both?
Edit: sample json (call: http://pokeapi.co/api/v1/pokemon/1/)
{
"abilities": [
{
"name": "overgrow",
"resource_uri": "/api/v1/ability/1/"
},
{
"name": "chlorophyll",
"resource_uri": "/api/v1/ability/2/"
}
],
"attack": 49,
"catch_rate": 45,
"created": "2013-11-02T12:08:25.745455",
"defense": 49,
"egg_cycles": 21,
"egg_groups": [
{
"name": "Monster",
"resource_uri": "/api/v1/egg/1/"
},
{
"name": "Grass",
"resource_uri": "/api/v1/egg/8/"
}
],
"ev_yield": "1 Sp Atk",
"evolutions": {
"level": 16,
"method": "level up",
"resource_uri": "/api/v1/pokemon/2/",
"to": "Ivysaur"
},
"exp": 64,
"growth_rate": "ms",
"happiness": 70,
"height": "2'4",
"hp": 45,
"male_female_ratio": "87.5/12.5",
"modified": "2013-11-02T13:28:04.914889",
"moves": [
{
"learn_type": "other",
"name": "Tackle",
"resource_uri": "/api/v1/move/1/"
},
{
"learn_type": "other",
"name": "Growl",
"resource_uri": "/api/v1/move/2/"
},
{
"learn_type": "level up",
"level": 10,
"name": "Vine whip",
"resource_uri": "/api/v1/move/3/"
}
],
"name": "Bulbasaur",
"national_id": 1,
"resource_uri": "/api/v1/pokemon/4/",
"sp_atk": 65,
"sp_def": 65,
"species": "seed pokemon",
"speed": 45,
"total": 318,
"types": [
{
"name": "grass",
"resource_uri": "/api/v1/type/5/"
},
{
"name": "poison",
"resource_uri": "/api/v1/type/8/"
}
],
"weight": "15.2lbs"
}
Evolutions class:
public class Evolutions
{
public int level { get; set; }
public string method { get; set; }
public string resource_uri { get; set; }
public string to { get; set; }
}
I tried http://json2csharp.com/ with http://pokeapi.co/api/v1/pokemon/19/ and what I see is
public class RootObject
{
//...
public List<Evolution> evolutions { get; set; }
//...
}
This pretty mush is your Pokemon class. So you need to declare Evolutions as list.

Categories