Read JSON Array that contains Arrays(?) C# - c#

I apologize in advance for the poor explanation of my problem.
I'm trying to read a JSON array that contains data.
Here's how the JSON looks:
{
"playerstats": {
"steamID": "76561198071680006",
"gameName": "GameName",
"achievements": [
{
"apiname": "AchievementName1",
"achieved": 0, <--- Data that I want to read
"unlocktime": 0
},
{
"apiname": "AchievementName2",
"achieved": 0, <--- Data that I want to read
"unlocktime": 0
},
{
"apiname": "AchievementName2",
"achieved": 1, <--- Data that I want to read
"unlocktime": 1477847680
}
]
,
"success": true
}
}
I'm trying to look at Newtonsoft.Json and how to use that yet I'm at a complete loss as to how to use this. Any help would be appreciated.

You can try JsonConvert.DeserializeObject to read json data.
Having
public class Rootobject
{
public Playerstats playerstats { get; set; }
}
public class Playerstats
{
public string steamID { get; set; }
public string gameName { get; set; }
public Achievement[] achievements { get; set; }
public bool success { get; set; }
}
public class Achievement
{
public string apiname { get; set; }
public int achieved { get; set; }
public int unlocktime { get; set; }
}
You can try this:
var filePath = path to your file;
var jsonData = System.IO.File.ReadAllText(filePath);
Rootobject objectValue =
Newtonsoft.Json.JsonConvert.DeserializeObject<Rootobject>(jsonData);
Note: you should remove <--- Data that I want to read parts from your json data because currently it is not a valid json format.
You may access to your desired properties like this
objectValue.playerstats.achievements[0].achieved //0
objectValue.playerstats.achievements[1].achieved //0
objectValue.playerstats.achievements[2].achieved //1

Related

Saving JSON to DataTable

I need to save data retrieved from API to a DataTable. JSON which is returned from API can't be deserialized directly to DataTable using this code:
DataTable dt = (DataTable)JsonConvert.DeserializeObject(json, (typeof(DataTable)));
I got an error: Unexpected JSON token when reading DataTable. I read that it's beacuse JSON format is not as it should be. Mine is as follows:
{
"page": 1,
"page_size": 1000,
"items": [
{
"id": "e1b019b9a8bf408c9cb964c29e845104",
"asset_id": "5adb0d87882b4e14b99bde74a967e84c",
"alias": "Concrete Pump Yellow",
"serial_number": "QEQ000123",
"model": {
"name": "Pump C50-HP"
},
"operating_hours": {
"hours": 100,
"unit_driven": true
}
}
]
}
I know I need format like [{..}] but can't find workaround, API returns JSON as above. I can deserialize it using this:
var obj = JsonConvert.DeserializeObject(json);
but how can I now add data to DataTable? I'm looking for a solution for it
What the JsonConvert class does is it materializes your string version of the response into an object. For this to work, your string version has to match the structure of the resulting object or the class needs hints to know how to inflate the object. The runtime is telling you that there is a mismatch and it doesn't know how to resolve it.
There are a few ways to get this done. I prefer an structured approach so I would recommend you create classes to receive the data:
var payload = #"{
""page"": 1,
""page_size"": 1000,
""items"": [
{
""id"": ""e1b019b9a8bf408c9cb964c29e845104"",
""asset_id"": ""5adb0d87882b4e14b99bde74a967e84c"",
""alias"": ""Concrete Pump Yellow"",
""serial_number"": ""QEQ000123"",
""model"": {
""name"": ""Pump C50-HP""
},
""operating_hours"": {
""hours"": 100,
""unit_driven"": true
}
}
]
}";
public class ApiResponse
{
[JsonProperty("page")]
public int Page { get; set; }
[JsonProperty("page_size")]
public int PageSize { get; set; }
[JsonProperty("items")]
public IEnumerable<ApiResponseItem> Items { get; set; }
}
public class ApiResponseItem
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("asset_id")]
public string AssetId { get; set; }
[JsonProperty("alias")]
public string Alias { get; set; }
[JsonProperty("serial_number")]
public string SerialNumber { get; set; }
[JsonProperty("model")]
public ApiResponseModel Model { get; set; }
[JsonProperty("operating_hours")]
public ApiResponseOperatingHours OperatingHours { get; set; }
}
public class ApiResponseModel
{
[JsonProperty("name")]
public string Name { get; set; }
}
public class ApiResponseOperatingHours
{
[JsonProperty("hours")]
public string Hours { get; set; }
[JsonProperty("unit_driven")]
public bool UnitDriven { get; set; }
}
var response = JsonConvert.DeserializeObject<ApiResponse>(payload);
As you can see, the classes use hint attributes to let the deserializer know about the fields. You can then loop through the response.Items enumerable and consume the items as desired.
UPDATE:
For posterity and at the suggestion of #mason, it's important to point out that there is no need to use a DataTable. A quick inspection of the payload reveals the output is a paged version of set of records so it's not equivalent to a data table.
Your issue here is that the json you're deserializing is not a DataTable, its just an Object.
JsonConvert.DeserializeObject(request, typeof(Object)) -> Where Object would be a defined Class with parameter definitions to deserialize the json to, i.e page, page_size, id etc..
Once in this format its fairly easy to coerce it into a DataTable:
https://learn.microsoft.com/en-us/dotnet/api/system.data.datatable?view=net-6.0
The Classes would look something along the lines of:
public class Items
{
public Guid? Id {get;set;}
public Guid? AssetId {get;set;}
public string alias {get;set;}
public string serial_number {get;set;}
public Model model {get;set;}
public OperatingHours operatingHours {get;set;}
}
public class Model
{
public string Name { get;set;}
}
public class OperatingHours
{
public int Hours {get;set;}
public bool Unit_Driven {get;set;}
}
public class OverallObject
{
public int Page {get;set;}
public int PageSize {get;set;}
public List<Items> AllItems {get;set;}
}

Retrieve data from JSON using JObject

I am attempting to get a value for a game from JSON, but there are multiple fields with the same name, so I was wondering whether there was a way in which I could just retrieve that individual value, here is the basic JSON structure:
"response": {
"game_count": 119,
"games": [
{
"appid": 3920,
"playtime_forever": 0
},
{
"appid": 4000,
"playtime_forever": 278
},
...
I need to somehow get a property by using an appID and then retrieving the playtime_forever key.
You can convert your JSON to class and then query:
class ResponseJSON
{
[JsonProperty("response")]
public Result Response { get; set; }
}
class Result
{
[JsonProperty("game_count")]
public string Count { get; set; }
[JsonProperty("games")]
public List<Game> Gmaes { get; set; }
}
class Game
{
[JsonProperty("appid")]
public string Id { get; set; }
[JsonProperty("playtime_forever")]
public string PlayTime { get; set; }
}
var resp = JsonConvert.DeserializeObject<ResponseJSON>(jsonstr);
And then you can iterate through your object with a for loop:
foreach(game in resp.Respone.Games) {
var playtime = game.PlayTime;
// do stuff here
}
Or you can use linq to query your games:
var selectiveGames = resp.Response.Games.Where(x=> x.PlayTime == 220).ToList();
You need to add newtonsoft dll from here to your project if you don't have it;
UPDATE: With original JSON the code above is working perfect.

Parse complex JSON: multiple loops vs. classes

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

C# JsonArray to string (not string array. string only)

I've been searching for this one for quite a while but can't find anything. Appologies then for the title, as there is a lot on converting content to String Arrays, which is not what I need.
I need a way to convert the contents of a JsonArray to string just as is. (Similar to JToken's .ToString()). My scenario is of such a nature that I need the string of an array just as is, irrigardless of the type/s contained within. There are ways of handling weakly typed json with ValueConverters, but I spesifically do not want to use them, as I need to pass the content of a field as a string to a Javascript Function in a WebView.
I have the following json (note markers indicating where string is desired) :
"highlights2":[
{
"_id":"highlight2-2850cb68121f9d4093e67950665c45fab02cec81",
"_rev":"9-c4345794001495104f8cbf5dd6999f3a",
"content":{ <---- Need this as string
"#roepman.17.0":[
[
233,
249,
"itsi-hl-gr"
],
[
298,
317,
"itsi-hl-bl"
]
],
"#roepman.19.0":[
[
5,
7,
"itsi-hl-gr"
]
]
}, <----- Up to here
"created":1434552587
}, //...more like this
],
"book":"book-930d62a2-9b7c-46a9-b092-f90469206900",
"serverTime":1435151280
Ideally I want to parse it into a list of the following type:
public class HighlightInfo2
{
public string _id { get; set; }
public string _rev { get; set; }}
public string content { get; set; }
public long created { get; set; }
}
However this is not possible, as the content of "content" is of type JsonArray. So to get past not having to specify a type for "content", I use this:
public class HighlightInfo2
{
public string _id { get; set; }
public string _rev { get; set; }}
public Dictionary<string, List<JsonArray>> content { get; set; }
public long created { get; set; }
}
But this means I still have to at some point convert the List< JsonArray > inside the dictionary to a string as I pass the content of "content" to a Javascript function in a webview later on.
Any way of converting the JsonArray to a string?
Based on your comment, the formatting of that string is irrelevant. It just has to be valid JSON representing the original data.
What I would suggest then is to make your content member in HighlightInfo2 of type object and simple perform a JsonConvert.SerializeObject(highlightInfo.content) to get the JSON string. This is what you can then pass over to the JavaScript function.
If you need to do this often, you can combine this with Behzad's answer and add another member to your class that stores this converted value.
What i suggest is to make another property like contentJson under highlightInfo2 class and put the string of jsonarray in it.
public class HighlightInfo2
{
private Dictionary<string, List<JsonArray>> _content;
public string _id { get; set; }
public string _rev { get; set; }
public Dictionary<string, List<JsonArray>> content
{
get { return _content; }
set
{
_content = value;
foreach (var item in _content)
{
contentJson += string.Join("\r\n", item.Value);
}
}
}
[JsonIgnore] //note, this depends on your json serializer
public string contentJson { set; get; }
public long created { get; set; }
}
Using a combination of Daniel's Answer and Behzad's Answer, I came up with this class/type for deserialization, which works without a hitch. Thanks for the help.
public class HighlightInfo2
{
public string _id { get; set; }
public string _rev { get; set; }
public long created { get; set; }
private JToken _content { get; set; }
public JToken content
{
get { return _content; }
set
{
_content = value;
contentString = JsonConvert.SerializeObject(value);
}
}
[JsonIgnore]
public string contentString { get; set; }
}

Difficulty with json string deserialization

I make a web request in Silverlight for windows phone. And this is the responce.
{"result": {
"account": null,
"checkInfo": null,
"command": null,
"shifts": [
{
"description": "17:45 - 17:55 work shift",
"id": 5459,
"venueId": 132
}]}}
I use Newtonsoft.Json.dll and my purpose is to catch the array - shifts.
JObject obj = JObject.Parse(StringShifts);
JArray sh = (JArray)obj["shifts"];
But every time sh value is null. What i'm i doing wrong? Thank you in advance.
The other way around is: (This is very helpful, if you are doing more operations like this in your project)
Create these classes in your project
public class Shift
{
public string description { get; set; }
public int id { get; set; }
public int venueId { get; set; }
}
public class Result
{
public object account { get; set; }
public object checkInfo { get; set; }
public object command { get; set; }
public List<Shift> shifts { get; set; }
}
public class RootObject
{
public Result result { get; set; }
}
And then in your code
var rootObject = JsonConvert.DeserializeObject<RootObject>(StringShifts);
foreach(var shift in rootObject.result.shifts)
{
Console.Write(shift.description);
}
This way you can have more control on your json response data. But L.B 's answer if it is one time process in your app.
var obj = (JObject)JsonConvert.DeserializeObject(json);
foreach (var shift in obj["result"]["shifts"])
{
Console.WriteLine((string)shift["description"]);
}
You are missing the root results node; this is how you should use it:
JArray sh = (JArray)obj["result"]["shifts"];
Also, do note that there is a missing } in the end of your JSON sample above!

Categories

Resources