Parse complex JSON: multiple loops vs. classes - c#

I have a Json of type :
{
"JobProcessors": [
{
"JobName": "ArchivalJob",
"IsEnabled": true,
"Batching": {
"BatchSize": 0,
"DegreeOfParallelism": -1
},
"Settings": {
"ArchivalJobCollectionPageSize": 50
}
},
{
"JobName": "AuditLogJob",
"IsEnabled": false,
"Batching": {
"BatchSize": 10,
"DegreeOfParallelism": -1
},
"Settings": {}
}
],
"ScheduledJobs": [
{
"JobName": "RemoteStartClientCommandJob",
"PrimaryAction": {
"ConnectionString": "#JobProcessorsIntegrationSBConnectionStringValue#",
"Settings": {
"LeadTimeInSeconds": "600",
"MaxSrsJobCount": 25
}
},
"ErrorAction": {
"ConnectionString": "#PairedJobProcessorIntegrationSBConnectionStringValue#",
"EntityPath": "remotestartqueue",
"Settings": {
"LeadTimeInSeconds": "600",
"MaxSrsJobCount": 25
}
}
}
]
}
I want to check the "IsEnabled" property for all "JobName" for which come under "JobProcessors" category.
In C# what i Have used till now is :
dynamic parsedJson = JsonConvert.DeserializeObject(reader.GetString(1));
foreach (var item in parsedJson)
{
foreach (var smallitem in item)
{
foreach (var tag in smallitem)
{
if(tag.IsEnabled.toString()=="true"){
Console.WriteLine("true");
}
}
}
}
This is giving me correct result except the fact that it also iterates for "ScheduledJobs" . But the main issue is :
Is this the right or most efficient way to do this ? If possible suggest some better method .
One that i know of is using classes , but i may not know the json structure beforehand. Also the json is very huge so making classes can be cumbersome !!

Given that you are already doing JObject.Parse(jsonstring); to parse your JSON string, you can use SelectTokens() with a JSONPath query to find all "JobName" objects under "JobProcessors":
// I want to check the "IsEnabled" property for all "JobName" for which come under "JobProcessors"
foreach (var job in root.SelectTokens("..JobProcessors[?(#.JobName)]"))
{
var isEnabled = (bool?)job["IsEnabled"];
Debug.WriteLine(string.Format("Job {0}: IsEnabled={1}", job["JobName"], isEnabled));
}
Notes:
.. is the recursive descent operator: it recursively descends the JToken hierarchy returning each item, subsequently to be matched against the remaining parts of the query string.
JobProcessors returns values of properties of that name.
[?(#.JobName)] returns array items (of JobProcessors in this case) that are objects with a JobName property.
(bool?) casts the value of "IsEnabled" to a boolean or null if missing.
And the output of this is:
Job ArchivalJob: IsEnabled=True
Job AuditLogJob: IsEnabled=False

As in your code snippet we are using two foreach it may take time for large object. So we can do the same thing in a single foreach or if you have some specific node to fetch or search we can use linq, and for this first we need to convert our json object into c# object. For converting Json object to C# you can use this site "http://json2csharp.com/" then we can Deserialize Json object into c#.
It will be something like this
string jsonString = "your Json Object as string";
var jsonObject = JsonConvert.DeserializeObject<RootObject>(jsonString);
foreach (JobProcessor obj in jsonObject.JobProcessors)
{
string JobName = obj.JobName;
bool value=obj.IsEnabled;
}
And I also converted given Json in c# object if the Json object is same you can directly use these classes.
public class Batching
{
public int BatchSize { get; set; }
public int DegreeOfParallelism { get; set; }
}
public class Settings
{
public int ArchivalJobCollectionPageSize { get; set; }
}
public class JobProcessor
{
public string JobName { get; set; }
public bool IsEnabled { get; set; }
public Batching Batching { get; set; }
public Settings Settings { get; set; }
}
public class Settings2
{
public string LeadTimeInSeconds { get; set; }
public int MaxSrsJobCount { get; set; }
}
public class PrimaryAction
{
public string ConnectionString { get; set; }
public Settings2 Settings { get; set; }
}
public class Settings3
{
public string LeadTimeInSeconds { get; set; }
public int MaxSrsJobCount { get; set; }
}
public class ErrorAction
{
public string ConnectionString { get; set; }
public string EntityPath { get; set; }
public Settings3 Settings { get; set; }
}
public class ScheduledJob
{
public string JobName { get; set; }
public PrimaryAction PrimaryAction { get; set; }
public ErrorAction ErrorAction { get; set; }
}
public class RootObject
{
public List<JobProcessor> JobProcessors { get; set; }
public List<ScheduledJob> ScheduledJobs { get; set; }
}
Hope this will help.
Thank you

Related

JArray to c# Object

I have this json string:
[
{
"id":"EORDERING_GRE017",
"name":"DELIMITER",
"value":"|"
},
{
"id":"EORDERING_GRE017",
"name":"ENABLED",
"value":"Y"
},
{
"id":"EORDERING_GRE017",
"name":"EXTERNALERRORRECIPIENT",
"value":"jaymie#moo.co.uk; matt#moo.co.uk"
},
{
"id":"EORDERING_GRE017",
"name":"FILETYPE",
"value":"delimited"
},
{
"id":"EORDERING_GRE017",
"name":"INTERNALERRORRECIPIENT",
"value":"jaymie#moo.co.uk; matt#moo.co.uk"
},
{
"id":"EORDERING_GRE017",
"name":"USESOWNBRANCHCODES",
"value":"True"
},
{
"id":"EORDERING_GRE017",
"name":"USESOWNSKUS",
"value":"True"
}
]
And I would like to turn that json into my class, which looks like this:
public class Settings
{
public bool Enabled { get; set; }
public string FileType { get; set; }
public string Delimiter { get; set; }
public string OrderFileSuffix { get; set; }
public string ResultFileSuffix { get; set; }
public bool UseOwnBranchCodes { get; set; }
public bool UseOwnProductCodes { get; set; }
public string InternalContacts { get; set; }
public string ExternalContacts { get; set; }
}
But I am unsure which is the best way to do this. Can someone give me a hand? :)
You could create a NameValue object:
public class NameValuePair
{
public string Name { get; set; }
public string Value { get; set; }
}
And deserialize the json array to List and convert it to Dictionary:
var dict = JsonConvert.DeserializeObject<List<NameValuePair>>(json).ToDictionary(x => x.Name, x => x.Value);
Then create a custom converter class with a method that accepts this dictionary and returns a Settings object:
public class SettingsConverter
{
public Settings Convert(IDictionary<string, string> data)
{
return new Settings
{
Enabled = data["ENABLED"].Equals("Y", StringComparison.Ordinal),
...
};
}
}
The JSON is an array of objects that would fit this class:
public class Setting
{
public string Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
So deserialize into that:
var settingList = JsonConvert.DeserializeObject<Setting[]>(jsonString);
But then you want to map specific settings to specific properties of that Settings class. You could do that by trying to find the particular setting for each property in the list of settings:
var settingsObject = new Settings
{
FileType = settingList.FirstOrDefault(s => s.Name == "FILETYPE")?.Value,
Delimiter = settingList.FirstOrDefault(s => s.Name == "DELIMITER")?.Value,
// ...
}
You'll have to manually map the properties. If you don't want that, you could write a custom serializer, but that'll quickly become a maintenance nightmare.
For those out there that may need some more help with the JSON Class Configuration, try: http://json2csharp.com/#
An excellent way of Auto Generating the Classes!
Or even easier, in VS, Goto:
Edit -> Paste Special -> Paste as JSON Classes

Derserialize JSON Object from Firebase in C#

I am querying Firebase and retrieve a collection of objects like so:
{"-K5f0ccEKkVkxTAavQKY": {
"Appeal": {
"ID": "1450273330435",
"comps": [
162248,
162272,
162273,
162281,
162544
],
"property": {
"Address": "15 Main Street",
"propID": 169729
},
"timeDateStamp": "Wed Dec 16 2015 08:42:10 GMT-0500 (Eastern Standard Time)",
"userUUID": "google:229139952703238437512",
"year": 2016
}
}}
I would like to deserialize them into objects with this definition:
public class Appeal
{
public string ID;
public List<string> comps;
public AppealProperty property;
public string timeDateStamp;
public string UUID;
public int year;
}
public class AppealProperty
{
public string address;
public string propID;
}
I have troubles getting it deserialized. I don't need the initial string (e.g. "K5f0ccEKkVkxTAavQKY"). I'm able to change the object definitions if need be. I have a feeling a Dictionary would be useful.
The quick and dirty object is to use Dictionary<string,Appeal> as your deserialization target. At that point it would be as simple as:
var firebaseLookup = JsonConvert.DeserializeObject<Dictionary<string,Appeal>>(json);
var data = firebaseLookup.Values.ToList(); // or FirstOrDefault();
This approach would also handle the case if you ever had to get multiple objects at once, and it would give you the opportunity to use that key if it turns out the key was important after all.
You could serialise your data into the classes below.
public class AppealProperty
{
public string Address { get; set; }
public int propID { get; set; }
}
public class Appeal
{
public string ID { get; set; }
public List<int> comps { get; set; }
public AppealProperty property { get; set; }
public string timeDateStamp { get; set; }
public string userUUID { get; set; }
public int year { get; set; }
}
public class FireBase
{
public Appeal Appeal { get; set; }
}
public class RootObject
{
[JsonProperty(PropertyName = " - K5f0ccEKkVkxTAavQKY")]
public FireBase FireBaseRoot
{
get;
set;
}
}
Assuming that you are using JSON.NET, you can then get the object you are after, using this snippet:
var firebaseObject = JsonConvert.DeserializeObject<RootObject>(json);
var data = firebaseObject.FireBaseRoot.Appeal;
If the root name is dynamic, as indicated by your comment, you could skip the root instead and serialise straight into the FireBase class:
JObject parsedJson = JObject.Parse(json);
var fireBase = parsedJson.First.Children().First().ToObject(typeof (FireBase));
Since I've never been able to parse a DataSnapshot with newtonSoft Json parser, I did this to build a list of object I needed to put in a ListView:
MyModelObject class
public class MyModelObject: Java.Lang.Object
{
public string Title { get; set; }
public string Description { get; set; }
public MyModelObject(){}
}
into My Listener
public void OnDataChange(DataSnapshot snapshot)
{
List<MyModelObjecct> myList = new List<MyModelObject>();
myList = databaseService
.GetMyModelObjectList(snapshot
.Children?
.ToEnumerable<DataSnapshot>());
}
Method into the DatabaseService class
public List<MyModelObject> GetMyModelObjectList(IEnumerable<DataSnapshot> enumerableSnapshot)
{
List<MyModelObject> list = new List<MyModelObject>();
foreach (var item in enumerableSnapshot)
{
list.Add(ObjectExtensions.DataSnapshotToObject<MyModelObject>(item.Children?.ToEnumerable<DataSnapshot>()));
}
return list;
}
ObjectExtensions class
public static class ObjectExtensions
{
public static T DataSnapshotToObject<T>(IEnumerable<DataSnapshot> source)
where T : class, new()
{
var someObject = new T();
var someObjectType = someObject.GetType();
foreach (var item in source)
{
someObjectType
.GetProperty(item.Key)
.SetValue(someObject, item.Value.ToString(), null);
}
return someObject;
}
}

Runtime Binder Exception

After a deserialization I save the content in an object:
var obj = JsonConvert.DeserializeObject<dynamic>(responseText);
so I execute a loop for populate a DataGrid
foreach(var item in obj)
{
MainWindow.AppWindow.Squadre_DataGrid.Items.Add(new Teams.Club_Information
{
code = item.code,
name = item.name,
shortName = item.shortName,
squadMarketValue = item.squadMarketValue
});
}
The problem's that inside the foreach the compiler show Runtime Binder Exception.
Why happean this?
Some more details:
Class structure
public class Self
{
public string href { get; set; }
}
public class Fixtures
{
public string href { get; set; }
}
public class Players
{
public string href { get; set; }
}
public class Links
{
public Self self { get; set; }
public Fixtures fixtures { get; set; }
public Players players { get; set; }
}
public class RootObject
{
public Links _links { get; set; }
public string name { get; set; }
public string code { get; set; }
public string shortName { get; set; }
public string squadMarketValue { get; set; }
public string crestUrl { get; set; }
}
JSON structure:
{
"_links": {
"self": { "href": "http://api.football-data.org/alpha/teams/19" },
"fixtures": { "href": "http://api.football-data.org/alpha/teams/19/fixtures" },
"players": { "href": "http://api.football-data.org/alpha/teams/19/players" }
},
"name": "Eintracht Frankfurt",
"code": "SGE",
"shortName": "Eintr. Frankfurt",
"squadMarketValue": "75.475.000 ?",
"crestUrl": "http://upload.wikimedia.org/wikipedia/commons/0/04/Eintracht_Frankfurt_Logo.svg"
}
The object you are deserializing does not contain a property named code. So the line code = item.code causes an exception at runtime, because the Json.Net object behind the dynamic does not contain a value named code.
This means that the Json that you are parsing does not contain a property named code. Or else it only sometimes contains a property named code. In that case you'll have to either parse it is a JObject and check if the property exists or create an type do deserialize it into.'
Edit
Based on the Json that you posted along with the class structure it looks like you should just be deserializing directly into a RootObject class:
var obj = JsonConvert.DeserializeObject<RootObject>(responseText);
Or in any case you can still deserialize into a dynamic but you need to get rid of the foreach since you don't have a collection of RootObject
var obj = JsonConvert.DeserializeObject<dynamic>(responseText);
MainWindow.AppWindow.Squadre_DataGrid.Items.Add(new Teams.Club_Information
{
code = obj.code,
name = obj.name,
shortName = obj.shortName,
squadMarketValue = obj.squadMarketValue
});
Where you went wrong was the foreach. Since obj is dynamic there is no compiler error and the Json.Net JObject that is returned supports iteraction. But the that gives you back each of the property values, (e.g. _links, name, etc) on at a time, not the object that you are interested in.

Deserialize Json like { List : { [ ... ], [ ... ] } }

It's my first work with Json.
I've already installed Json.Net in my Visual Studio project and used to deserialize some simple string like this:
{
"A":"1",
"B":"2",
"C":"3"
}
With this code:
JToken token = JObject.Parse("{ "A":"1","B":"2","C":"3"}";
string aValue = token.SelectToken("A");
string aValue = token.SelectToken("B");
string aValue = token.SelectToken("C");
But I don't know how to do with a Json like this:
{
"LIST":[
{
"A":"value1",
"B":"value1",
"C":"value1"
}
{
"A":"value2",
"B":"value2",
"C":"value2"
}
{
"A":"value3",
"B":"value3",
"C":"value3"
}
],
"D":"value4",
"E":"value5",
"F":"value6"
}
How can get all elements of type and the other variable like D, E and F?
Thank you
The easiest way would be to create objects and deserialize into those:
public class Parent
{
public Child[] LIST { get; set; }
public string D { get; set; }
public string E { get; set; }
public string F { get; set; }
}
public class Child
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
Once you have your classes defined, deserializing your JSON is as easy as:
var p = JsonConvert.DeserializeObject<Parent>(json);
#Justin's answer is good and will work well. However, if you want to continue using the LINQ-to-JSON API style as you are doing now, here is how you can get all the info:
JToken token = JToken.Parse(jsonString);
foreach (JToken t in token["LIST"])
{
Console.WriteLine(t["A"]);
Console.WriteLine(t["B"]);
Console.WriteLine(t["C"]);
}
Console.WriteLine(token["D"]);
Console.WriteLine(token["E"]);
Console.WriteLine(token["F"]);

nested json c# object deserialization

i have the following json string (jsonString)
[
{
"name":"Fruits",
"references":[
{"stream":{"type":"reference","size":"original",id":"1"}},
],
"arts":[
{"stream":{"type":"art","size":"original","id":"4"}},
{"stream":{"type":"art","size":"medium","id":"9"}},
]
}
]
and the following C# objects
class Item
{
public string Name { get; set; }
public List<Stream> References { get; set; }
public List<Stream> Arts { get; set; }
public Item()
{
}
}
class Stream
{
public string Type { get; set; }
public string Size { get; set; }
public string Id { get; set; }
public Stream()
{
}
}
and the following code
Item item = JsonConvert.DeserializeObject<Item>(jsonString);
when I run the code, it creteas the correct number of references and arts, but each stream has null value (type = null, size = null).
is it posible to do this json.net deserializeobject method or should I manually deserialize ?
EDIT: Okay, ignore the previous answer. The problem is that your arrays (references and arts) contain objects which in turn contain the relevant data. Basically you've got one layer of wrapping too many. For example, this JSON works fine:
[
{
"name":"Fruits",
"references":[
{"Type":"reference","Size":"original","Id":"1"},
],
"arts":[
{"Type":"art","Size":"original","id":"4"},
{"type":"art","size":"medium","id":"9"},
]
}
]
If you can't change the JSON, you may need to introduce a new wrapper type into your object model:
public class StreamWrapper
{
public Stream Stream { get; set; }
}
Then make your Item class have List<StreamWrapper> variables instead of List<Stream>. Does that help?

Categories

Resources