How to deserialize this JSON to C# Class - c#

i'am working with a WebAPI that returns this json from a Request
{
"apps": {
"570": {
"228983": {
"8124929965194586177": "available"
},
"228990": {
"1829726630299308803": "available"
},
"373301": {
"840315559245085162": "available"
},
"373302": {
"688854584180787739": "available"
},
"373303": {
"3675525977143063913": "available"
},
"373305": {
"4435851250675935801": "available"
},
"381451": {
"6984541794104259526": "available"
},
"381452": {
"1442783997179322635": "available"
},
"381453": {
"6878143993063907778": "available"
},
"381454": {
"7824447308675043012": "available"
},
"381455": {
"5681120743357195246": "available"
}
},
"674940": {
"674941": {
"6246860772952658709": "available"
}
}
}
}
It returns A list of AppID (int), that contains another list of DepotID, that it Contains a ManifestID (Key) and if it's aviable or not (Value).
And i want to deserialize to a class to easy work with it, but i can't imagine how to do it. I'am a newbie in C# comming from C/C++

You can use Json.NET which is a popular JSON library for C#. See Deserialize an Object.
Example:
public class MyData
{
public Dictionary<long, Dictionary<long, Dictionary<long, string>>> apps { get; set; }
}
var data = JsonConvert.DeserializeObject<MyData>(json);
// Use 'data.apps'

I'm not sure how much is gained by modeling this as C# classes without property names beyond the "apps" level of your Json, but you could do it like so:
Model your Json with the following classes:
public class AppIds : Dictionary<string, DepotId> { }
public class DepotId : Dictionary<string, ManifestId> { }
public class ManifestId : Dictionary<string, string> { }
And then you can do like so using Newtonsoft.Json
class Program
{
static void Main(string[] args)
{
string jsonPath = #"c:\debug\data.json";
System.IO.Stream s = new System.IO.FileStream(jsonPath,System.IO.FileMode.Open, System.IO.FileAccess.Read);
AppIds data = JsonConvert.DeserializeObject<Dictionary<string, AppIds>>(File.ReadAllText(jsonPath))["apps"];
}
}

You can use the Newtonsoft.Json NuGet package and deserialize your data to a nested dictionary like so:
var data = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>>(File.ReadAllText("Data.json"));
To make sure you got the right data you can run this code to print it out:
foreach (var a in data)
{
Console.WriteLine(a.Key);
foreach (var b in a.Value)
{
Console.WriteLine("\t" + b.Key);
foreach (var c in b.Value)
{
Console.WriteLine("\t\t" + c.Key);
foreach (var d in c.Value)
{
Console.WriteLine("\t\t\t" + d.Key + ": " + d.Value);
}
}
}
}
Not really sure how to deserialize this data to a class since it doesn't have much in the way of property names...

Related

Deserializing JSON with numbers as field using JsonSerializer

I need to deserialize this weird JSON (image below). I've seen some deserialization hints using Dictionary<>, etc. but the problem is that "parameters" contains different data, then previous keys.
Can I somehow get it to work using JsonSerializer deserializator without doing foreach loops and other suspicious implementations? I do need data from "data" in my application.
Here's some of my code:
using var client = new WebClient();
var json = client.DownloadString(GetJsonString());
var invoicesData = JsonSerializer.Deserialize<JsonMyData>(json, options);
If using Newtonsoft is necessary I might start using it.
With Newtonsoft you can parse and access arbitrary JSON documents, even ones that can't reasonably be deserialized into a .NET object. So something like:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
namespace ConsoleApp35
{
class Program
{
static void Main(string[] args)
{
var json = #"
{
""myData"" :
{
""0"" : { ""data"": { ""A"":1,""B"":2} },
""1"" : { ""data"": { ""A"":1,""B"":2} },
""2"" : { ""data"": { ""A"":1,""B"":2} },
""3"" : { ""data"": { ""A"":1,""B"":2} },
""parameters"" : { ""p"":""a""}
},
""status"":{ }
}";
var foo = JObject.Parse(json);
var a = foo["myData"]["1"]["data"];
Console.WriteLine(a);
Console.WriteLine("Hit any key to continue");
Console.ReadKey();
}
}
}
I think you should really consider using Newtonsoft.Json instead of default JsonDeserializer, it is much easier to use in such situations.
If you are interested in processing this without foreach loops and wanting to access the data in a list format, I would suggest using Dictionary for this. When you use dictionary, you can use Objects as values that would compensate for differences in numbers (0, 1, 2, ..) and words (parameters).
// Classes to Deserialize data we need.
public class MyObject
{
[JsonProperty("data")]
public Data Data { get; set; }
}
public class Data
{
public int A { get; set; }
public int B { get; set; }
}
Usage in Main
// Read in the JSON
var myData = JsonConvert.DeserializeObject<dynamic>(jsonString)["myData"];
// Convert To Dictionary
Dictionary<string, dynamic> dataAsObjects = myData.ToObject<Dictionary<string, dynamic>>();
string searchFor = "3";
dataAsObjects.TryGetValue(searchFor, out dynamic obj);
if (obj != null)
{
// Conversion to int and matching against searchFor is to ensure its a number.
int.TryParse(searchFor, out int result);
if (result == 0 && result.ToString().Equals(searchFor))
{
MyObject myObject = obj.ToObject<MyObject>();
Console.WriteLine($"A:{myObject.Data.A} - B:{myObject.Data.B}");
}
else if (result == 8 && result.ToString().Equals(searchFor))
{
// I am not clear on whats your parameters class look like.
MyParameters myParams = obj.ToObject<MyParameters>();
}
}
Output
A:1 - B:2
With this method you can either access the numbers or the parameters element.

How to iterate through JObject Properties via Foreach/LINQ

I have an established JObject object. Trying to loop through it to acquire a Key/value based on anothers Key/value (example of json below with code currently stuck on)
For a tad more detail - looking to loop through "value", get the "KeyID" based on "MailState"
definitely feel like I am missing the step of filtering by MailState/ColName apparently - I have searched through threads a bunch but if someone knows of one that answered this that i was unable to find i will happily pull this down/reference it
// JSON DATA
{
"odata.metadata": "https://..com/odata/$metadata#JCJMCDXes",
"value": [
{
"KeyID": "10379",
"MailCity": "Chicago",
"MailState": "IL"
},
{
"KeyID": "9846",
"MailCity": "Chicago",
"MailState": "IL"
},
{
"KeyID": "2234",
"MailCity": "Madison",
"MailState": "WI"
}]
}
// Current code example
// class in play
public class datastorage
{
public string ID { get; set; }
public string Col { get; set; }
}
public class listData
{
public string ColName {get;set;}
}
// getVPData is a string response from a call to an API
getVPData.Replace(System.Environment.NewLine, "");
JObject jobj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(getVPData);
List<datastorage> data = new List<datastorage>();
// Loop
foreach(var r in listData) // has distinct State abeviations so only 1 occurence
{
foreach (var j in jobj) // This the right path?
{
//add KeyID into ID
data.add(new datastorage
{
ID = ,//add KeyID into ID
Col = r.ColName
});
}
}
You can use Newtonsoft.Json library to parse and loop to the items of value
here is a sample code:
dynamic json = JsonConvert.DeserializeObject(getVPData);
foreach (dynamic item in json["value"])
{
//you can access the fields inside value.
var KeyID = item["KeyID"];
var MailCity = item["MailCity"];
var MailState = item["MailState"];
//just for showing...
Console.WriteLine("KeyID:{0}, MailCity:{1}, MailState:{2}", KeyID, MailCity, MailState);
}
Let me know if the snippet works.
Straightforward ways are:
using System;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ConsoleApp7
{
internal class Program
{
private static void Main(string[] args)
{
var mailStates = new[] {"IL", "WI"};
var jObject = (JObject) JsonConvert.DeserializeObject(json);
var values = (JArray) jObject["value"];
// 1st way
foreach (var mailState in mailStates)
{
var key = values
.Where(v => mailState == v.SelectToken("MailState").Value<string>())
.Select(v => v.Value<string>("KeyID"))
.FirstOrDefault();
Console.WriteLine($"1st case: {mailState} - {key}");
}
/* 2nd way based on JSONPath
* api: https://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm
* dox: https://support.smartbear.com/alertsite/docs/monitors/api/endpoint/jsonpath.html
* tester: https://jsonpath.curiousconcept.com/
*/
foreach (var mailState in mailStates)
{
var key = values.SelectTokens($"$[?(#.MailState == '{mailState}')].KeyID")
.Select(v => v.ToString())
.FirstOrDefault();
Console.WriteLine($"2nd case: {mailState} - {key}");
}
Console.ReadKey();
}
private static string json = #"
{
""odata.metadata"": ""https://cdxapiclient.palmercg.com/odata/$metadata#JCJMCDXes"",
""value"": [
{
""KeyID"": ""10379"",
""MailCity"": ""Chicago"",
""MailState"": ""IL""
},
{
""KeyID"": ""9846"",
""MailCity"": ""Chicago"",
""MailState"": ""IL""
},
{
""KeyID"": ""2234"",
""MailCity"": ""Madison"",
""MailState"": ""WI""
}]
}";
}
}

Howto C# DeserializeObject, where variable name is number?

How do I Deserialize the following. The problem is that the variable name is a number. So how should MyClass be defined?
json_str:
{"23521952": {"b": [], "o": []}, "23521953": {"b": [], "o": []}}
class MyClass { //? };
var var = JsonConvert.DeserializeObject<MyClass>(json_str);
This sounds like the outer object is actually a dictionary:
using System.Collections.Generic;
using Newtonsoft.Json;
class Foo
{
// no clue what b+o look like from the question; modify to suit
public int[] b { get; set; }
public string[] o { get; set; }
}
static class P
{
static void Main()
{
var json = #"{""23521952"": {""b"": [], ""o"": []}, ""23521953"": {""b"": [], ""o"": []}}";
var obj = JsonConvert.DeserializeObject<Dictionary<string, Foo>>(json);
foreach(var pair in obj)
{
System.Console.WriteLine($"{pair.Key}, {pair.Value}");
}
}
}
You can use anonymous type deserialization for your data like this, without creating classes for properties of JSON. Hope it works.
var finalResult=JsonConvert.DeserializeAnonymousType(
json_str, // input
new
{
Id=
{
new
{
b=new[], o=new[]
}
}
}
);
foreach(var id in finalResult.Id)
{
console.write(id); // gives ids like 23521952
console.write(id.b[0]) // gives first elemnt in 'b' array
}

C# Json To Dictionary of Objects

I want to take some Json and parse it in to a collection of key/value pairs, but some of the values will be dictionaries themselves. I tried the usual Newtonsoft deserialization. It's close, but not quite right. The end result must be a dictionary, not a strongly typed class.
This is some example Json:
{
"JobNumber": 1010,
"Asset": null,
"JobNotes": [
{
"NoteText": "It's not working.",
"NoteType": "Complaint"
},
{
"NoteText": "Needs to be fixed",
"NoteType": "Job"
}
]
}
This is the code I used to deserialize:
var json = File.ReadAllText(#"c:\temp\job.json");
var result = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
The result is almost correct, but the value of the item with a key of "JobNotes" is just json string. I want the parser to recurse in and deserialise the inner Json to a further dictionary of strings and objects. Is there a way I can do this with the Newtonsoft library? Or, is there another library that will do the trick? Can I hook in to the parsing method to override the functionality at that point in time?
This is a modified version of #DanielKeogh's code. It works well.
class Program
{
static void Main(string[] args)
{
var json = File.ReadAllText(#"c:\temp\job3.json");
var result = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
RecurseDeserialize(result);
}
private static void RecurseDeserialize(Dictionary<string, object> result)
{
//Iterate throgh key/value pairs
foreach (var keyValuePair in result.ToArray())
{
//Check to see if Newtonsoft thinks this is a JArray
var jarray = keyValuePair.Value as JArray;
if (jarray != null)
{
//We have a JArray
//Convert JArray back to json and deserialize to a list of dictionaries
var dictionaries = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(jarray.ToString());
//Set the result as the dictionary
result[keyValuePair.Key] = dictionaries;
//Iterate throught the dictionaries
foreach (var dictionary in dictionaries)
{
//Recurse
RecurseDeserialize(dictionary);
}
}
}
}
}
This modified Json shows how deep it goes:
{
"JobNumber": 1010,
"Asset": null,
"JobNotes": [
{
"NoteText": "It's not working.",
"NoteType": "Complaint"
},
{
"NoteText": "Needs to be fixed",
"NoteType": "Job",
"JobNoteNotes": [
{
"Something": 1,
"Something2": "Test"
}
]
}
]
}
The result ends three dictionaries deep so that I can get at the "Something" value by key.
This can be done with a little recursion. I'll leave defining IsJson up to you as an academic exercise. :)
Dictionary<string, object> RecursiveDeserialize(string json)
{
var result = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
foreach (var pair in result.ToArray())
{
if(IsJson(pair.Value))
{
result[pair.Key] = RecursiveDeserialize(pair.Value);
}
}
return result;
}
Using this object for json string
public class JobNote
{
public string NoteText { get; set; }
public string NoteType { get; set; }
}
public class ListJob
{
public int JobNumber { get; set; }
public object Asset { get; set; }
public List<JobNote> JobNotes { get; set; }
}
Then you can deserialize it

How to deserialise a JSON object where the object structure is not known

Part of my code serializes file paths of a machine into JSON in the below format. I am struggling to take this JSON and put the file paths back together again. I am using Newtonsoft JSON lib; I find it's excellent for building JSON. As you can see, my JSON has nested objects.
The JSON I have:
{
".": {
"proc": {
"15": {
"task": {
"15": {
"exe": {},
"mounts": {
"list_of_files": [
"mounts.xml"
]
},
"mountinfo": {
"list_of_files": [
"mountinfo.xml"
]
},
"clear_refs": {
"list_of_files": [
"clear_ref.xml"
]
}
}
}
},
"14": {
"loginuid": {
"list_of_files": [
"loginuid.xml"
]
},
"sessionid": {
"list_of_files": [
"sessionid.xml"
]
},
"coredump_filter": {
"list_of_files": [
"coredump_filter.xml"
]
},
"io": {
"list_of_files": [
"io.xml"
]
}
}
}
}
}
The array I want to generate from this.
string[] dirArray = {
"./proc/15/task/15/exe",
"./proc/15/task/15/mounts/mounts.xml",
"./proc/15/task/15/mountinfo/mountinfo.xml",
"./proc/15/task/15/clear_refs/clear_ref.xml",
"./proc/14/loginuid/loginuid.xml",
"./proc/14/sessionid/sessionid.xml",
"./proc/14/coredump_filter/coredump_filter.xml",
"./proc/14/io/io.xml"
}
My efforts so far-- I deserialised the JSON into a dynamic variable but I'm not sure how to handle two issues:
My JSON format is unknown, I don't know how deep the objects go, how can I handle this?
How do I work with dynamic variables when they are defined at run-time?
EDIT
Sorry, my original JSON format was wrong, so it doesn't work with the answer provided by user12864. I'm getting an error: Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to type 'Newtonsoft.Json.Linq.JObject'.
Here is a fiddle showing where I'm at so far.
#user12864 has the right idea in his answer, but the code needs to be adjusted to account for the fact that each directory can have an array of files rather a single "file" object (you really should have mentioned that in your question originally). Here is an updated method to handle that:
private static void AddToFileList(JObject jo, List<string> list, string prefix)
{
foreach (var kvp in jo)
{
if (kvp.Key == "list_of_files")
{
foreach (string name in (JArray)kvp.Value)
{
list.Add(prefix + name);
}
}
else
{
JObject dir = (JObject)kvp.Value;
if (dir.Count == 0)
{
list.Add(prefix + kvp.Key);
}
else
{
AddToFileList(dir, list, prefix + kvp.Key + "/");
}
}
}
}
Full demo:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
class Program
{
static void Main(string[] args)
{
string json = #"
{
""."": {
""proc"": {
""15"": {
""task"": {
""15"": {
""exe"": {},
""mounts"": {
""list_of_files"": [
""mounts.xml""
]
},
""mountinfo"": {
""list_of_files"": [
""mountinfo.xml""
]
},
""clear_refs"": {
""list_of_files"": [
""clear_ref.xml""
]
}
}
}
},
""14"": {
""loginuid"": {
""list_of_files"": [
""loginuid.xml""
]
},
""sessionid"": {
""list_of_files"": [
""sessionid.xml""
]
},
""coredump_filter"": {
""list_of_files"": [
""coredump_filter.xml""
]
},
""io"": {
""list_of_files"": [
""io.xml""
]
}
}
}
}
}";
JObject jo = JObject.Parse(json);
foreach (string path in CreateFileList(jo))
{
Console.WriteLine(path);
}
}
private static List<string> CreateFileList(JObject jo)
{
List<string> ret = new List<string>();
AddToFileList(jo, ret, "");
return ret;
}
private static void AddToFileList(JObject jo, List<string> list, string prefix)
{
foreach (var kvp in jo)
{
if (kvp.Key == "list_of_files")
{
foreach (string name in (JArray)kvp.Value)
{
list.Add(prefix + name);
}
}
else
{
JObject dir = (JObject)kvp.Value;
if (dir.Count == 0)
{
list.Add(prefix + kvp.Key);
}
else
{
AddToFileList(dir, list, prefix + kvp.Key + "/");
}
}
}
}
}
Output:
./proc/15/task/15/exe
./proc/15/task/15/mounts/mounts.xml
./proc/15/task/15/mountinfo/mountinfo.xml
./proc/15/task/15/clear_refs/clear_ref.xml
./proc/14/loginuid/loginuid.xml
./proc/14/sessionid/sessionid.xml
./proc/14/coredump_filter/coredump_filter.xml
./proc/14/io/io.xml
Fiddle: https://dotnetfiddle.net/r8CkI2
This should give exactly what you're looking for; just create a JObject with JObject.Parse and pass it to CreateFileList. It won't handle malformed JSON in any nice way.
static List<string> CreateFileList(JObject j)
{
List<string> ret = new List<string>();
AddToFileList(j, ret, "");
return ret;
}
static void AddToFileList(JObject j, List<string> dest, string prefix)
{
if (prefix.Length != 0)
prefix = prefix + '/';
foreach (var kvp in j)
{
var jnext = (JObject)kvp.Value;
if (kvp.Key == "file")
dest.Add(prefix + (string)jnext["name"]);
else
AddToFileList(jnext, dest, prefix + kvp.Key);
}
}
Fiddle at https://dotnetfiddle.net/dQQ4tI
Update:
Here is a revised answer, after you clarified your requirement of:
The JavaScript Object Notation is built on the server, edited by user through a hierarchical tree interface component. That can be crawled incredibly easy.
So in essence your utilizing a component, in which your hoping to build simple JavaScript Object Notation derived from the component. Your User Interface will be unknown, so I'll make some presumptions.
Build our Object:
public class XmlPath
{
public string Location { get; set; }
}
The XmlPath will represent our object. Which will be basic auto property.
Add Content to our Object:
private List<XmlPath> AddXmlPath(List<string> location)
{
List<XmlPath> content = new List<XmlPath>();
foreach(string item in location)
content.Add(new XmlPath() { Location = item });
return content;
}
This will be incredibly simple method, it will take a large List<string> of your user data and add them to your XmlPath object.
Remove content from our Object:
private List<XmlPath> RemoveXmlPath(List<XmlPath> root, string location)
{
root.Remove(new XmlPath() { Location = location });
return root;
}
Those two methods truly don't need to be, I'm just demonstrating and showing how you could. Plus it will outline the intentions a bit easier for you to implement. Please note this is incredibly crude approach.
Serialize / Deserialize Our Object to JavaScript Objection Notation:
JavaScriptSerializer serializer = new JavaScriptSerializer();
var xmlPath = AddXmlPath(List<string> location);
var result = serializer.Serialize(xmlPath);
var deserialize = serializer.Deserialize(List<XmlPath>>(result);
Our content is exposed now through a basic loop:
foreach(XmlPath item in deserialize)
{
// Exposed Model via 'item.Location'
}
You'll simply need to correlate this core functionality to your implementation. The approach is crude, quite rudimentary, definitely will need to be improved on for production. However this should get you started with:
Serialize data on the server.
Deserialize server data.
Manipulating the object.
Hope this is better for you.

Categories

Resources