Parsing nested Json data with C#. Could not access inner element consumption - c#

I can parse up to one nested level but I'm unable to figure out how to read the data in the consumption_history. I have been trying different ways to do it but could not get the consumption value.
I can access the miu_id and meter_number but not the array of consumption_list.
Model:
class JsonModel
{
public class Rootobject
{
public string site_id { get; set; }
public Endpoint[] endpoints { get; set; }
public Paging paging { get; set; }
}
public class Paging
{
public int page { get; set; }
public int limit { get; set; }
public int total { get; set; }
public string next { get; set; }
public object prev { get; set; }
public string self { get; set; }
}
public class Endpoint
{
public string miu_id { get; set; }
public string meter_number { get; set; }
public Consumption_History[] consumption_hist { get; set; }
}
public class Consumption_History
{
public DateTime reading_date { get; set; }
public float consumption { get; set; }
public float consumption_with_multiplier { get; set; }
}
}
Program:
static void Main(string[] args)
{
string json = File.ReadAllText(#"C:\Users\ConsoleApp3\apidataone.json");
var results = JsonConvert.DeserializeObject<JsonModel.Rootobject>(json);
JsonModel.Rootobject rootobject = JsonConvert.DeserializeObject<JsonModel.Rootobject>(json);
rootobject.endpoints = JsonConvert.DeserializeObject<JsonModel.Rootobject>(json).endpoints;
foreach (JsonModel.Consumption_History ch in rootobject.endpoints)
{
Console.WriteLine(ch.consumption);
}
}
json data:
{
"site_id":"1",
"endpoints":
[{
"miu_id":"111",
"meter_number":"88",
"consumption_history":
[{
"reading_date":"2010-02-17T00:00:00",
"consumption":1.0,
"consumption_with_multiplier":1.0
}]
}]
}

I have simplified the code a bit, instead of reading from a file I have just put the JSON content in place. This code uses Newtonsoft.Json (available via NUGET package), but the way it works is the same for other serializers.
// using Newtonsoft.Json;
void Main()
{
string json = #"{
'site_id':'1',
'endpoints':
[{
'miu_id':'111',
'meter_number':'88',
'consumption_history':
[{
'reading_date':'2010-02-17T00:00:00',
'consumption':1.0,
'consumption_with_multiplier':1.0
}]
}]
}";
dynamic j = JsonConvert.DeserializeObject<dynamic>(json);
string site_id = j["site_id"].ToString();
var endpoints = j["endpoints"];
foreach (var endpoint in endpoints)
{
string miu_id = endpoint["miu_id"];
miu_id.Dump();
// ...
var consumption_histories = endpoint["consumption_history"];
foreach(var consumption in consumption_histories)
{
string reading_date = consumption["reading_date"];
reading_date.Dump();
// ...
} // foreach
} // foreach
}
Run it in .NET fiddle
Regarding JSON: Whenever there is a [ ... ] in the JSON structure, this means there is an array ({ ... } stands for an object) - and [{ ... }] is an object inside an array; both properties and array elements are separated by comma (,); strings and property names need to be enclosed in single quotes ('...'). Value assignments are done with a colon (:). In JSON, you have either objects, strings or numeric data - these are the only types existing. If you need types, you have to cast properties into the proper types by yourself.
You can access the array either via indexer (like endpoints[i] inside a for loop), or - as I am assuming - you want to go through every element, in that case a foreach loop is easier.
Note: To use it in a for loop (like for (int i = 0; i < endpointsLength; i++) { ... }), you would have to cast endpoints and consumption_histories into an array type (e.g. via var endpoints = (object[])j["endpoints"];) and lose the simplicity dynamic provides (for example, then you would need an indexer to access a property like (endpoints[i])["miu_id"] to be able to get the value of miu_id).
The keyword dynamic simplifies things a lot in this case, this way you can keep the "JavaScript-Style" of the C# code (remember JSON comes from the JavaScript world).
If you want to introduce the classes you have declared in C#, this is also possible. For example:
foreach (Consumption_History consumption in consumption_histories)
{
string reading_date = consumption.reading_date.ToString();
reading_date.Dump();
// ...
} // foreach
You can see, that reading_date is now being accessed as C# property, and because it is of type DateTime, you need to cast it into a string first. This conversion needs to be done before the foreach loop, so you can either change the data type in your class to string to avoid that, or you can use the original code shown above and copy + convert the data into typed versions of your objects (for converting a string into DateTime, you can check this out).
If you rely on the built-in conversion NewtonSoft.JSON provides, you can simply use JsonConvert.DeserializeObject<Rootobject>(json) instead of JsonConvert.DeserializeObject<dynamic>(json). Note that implicit conversions can throw exceptions.
Also, make sure that the property names in C# and in your JSON file match exactly - if not you can decorate them in C# using attributes (see here for a description how to do that) - xdtTransform found that it is not matching for consumption_hist, and mentioned it in the comments.

Related

serialization issue with json structure using newtonsoft

This is an old application (.Net 4.5).
I am following the guide here: https://weblog.west-wind.com/posts/2012/aug/30/using-jsonnet-for-dynamic-json-parsing
My goal is to have a way to store a flexible json structure without tying it down to a static structure. For example, in the TriggerJson below, the actual Trigger field is of type string, which is supposed to be json. That json structure could reflect ExpiryTriggerJson, or some other structure which is determined by TriggerType.
I have the following structure:
public class TriggerJson
{
public string TriggerType { get; set; }
public string ConfiguredBy { get; set; }
public string Trigger { get; set; }
}
public class ExpiryTriggerJson
{
public string ActionType { get; set; }
public TriggerRecipient[] Recipients { get; set; }
}
public class TriggerRecipient
{
public string Id { get; set; }
public string Name { get; set; }
public bool IsTag { get; set; }
}
In the following code, I am creating a list of TriggerJson such that each element's Trigger field be a json structure made from ExpiryTriggerJson object:
var tjList = new List<TriggerJson>();
var triggerJson = new TriggerJson();
triggerJson.TriggerType = TriggerJsonHelper.ExpiryTriggerType;
triggerJson.Trigger = JsonConvert.SerializeObject(new ExpiryTriggerJson
{
Recipients = taskRecipients,
ActionType = TriggerJsonHelper.ExpiryTriggerActionType_Task
});
triggerJson.ConfiguredBy = configuredBy;
tjList.Add(triggerJson);
fieldValue.TriggersJson = JsonConvert.SerializeObject(tjList);
This creates the following structure for example where Trigger field reflects a serialized structure which has escaped double quotes due to double serialization:
[{"TriggerType":"ExpiryTrigger","ConfiguredBy":"acd1ac353ac44e078aaef8ce6479a4c6","Trigger":"{\"ActionType\":\"CreateReminderTask\",\"Recipients\":[{\"Id\":\"70050a95-f31b-41b7-9b49-0688fa76dba5\",\"Name\":\"blah blah\",\"IsTag\":false}]}"}]
This creates a problem for me when trying to deserialize this data later on when reading it back:
JArray jsonObj = JArray.Parse(triggersJson);
foreach (dynamic obj in jsonObj)
{
if (obj.TriggerType == ExpiryTriggerType)
{
ExpiryTriggerJson triggerData = obj.Trigger.ToObject<ExpiryTriggerJson>();
The above code tries to parse back ExpiryTriggerJson structure that was first assigned to the field Trigger of TriggerJson element. This throws a runtime deserialization exception when executing the last line trying to convert to ExpiryTriggerJson which I suspect happens due to double deserialization.
My question is how do I accomplish my goal of storing static/structural json data as a string and then parse it back in a nested manner?
This might be what you want.
public dynamic Trigger {get;set;}
Then trigger will be resolved to whatever type it receives at runtime.

Retrieving Mixpanel data from JSON in C#

I am trying to get data from a Mixpanel API. The JSON result looks like this:
{"computed_at": "2019-11-19T10:36:33.908802+00:00", "legend_size": 1, "data": {"series": ["2019-11-11", "2019-11-12", "2019-11-13"], "values": {"page views": {"2019-11-12": 111, "2019-11-11": 573, "2019-11-13": 209}}}}
I am struggling with nested JSON (despite looking at a fair few StackOverflow articles on this) and I want to try and get the values 111,573 and 209 for the page views. How do I access these values?
I've tried the following:
var result = {"computed_at": "2019-11-19T10:36:33.908802+00:00", "legend_size": 1, "data": {"series": ["2019-11-11", "2019-11-12", "2019-11-13"], "values": {"page views": {"2019-11-12": 111, "2019-11-11": 573, "2019-11-13": 209}}}}
var rawData = result["data"]["values"]["page views"][0]
but this doesn't work and I can't figure out how to access the individual values. Can anyone help please?
EDIT:
When using the json to C# converter (as suggested in the comments to this post) the outcome is as follows:
public class PageViews
{
public int __invalid_name__2019-11-20 { get; set; }
public int __invalid_name__2019-11-19 { get; set; }
}
public class Values
{
public PageViews __invalid_name__page views { get; set; }
}
public class Data
{
public List<string> series { get; set; }
public Values values { get; set; }
}
public class RootObject
{
public DateTime computed_at { get; set; }
public int legend_size { get; set; }
public Data data { get; set; }
}
and I am still unsure how to get the numbers from this?
There are two approaches you could take. First, I'd deserialize the json string using this library - Newtonsoft.
You can then go through the json using JObjects, or you can create a C#-Class that represents your json data and then deserialize it into a corresponding object.
Via a class:
To create the json class there is this website, which creates the classes (also nested) just as the json needs them to be: http://json2csharp.com/
Then you use:
var myObject = JsonConvert.DeserializeObject<MyClass>(jsonString);
and then simply go through your object properties.
Via JObject
JObjects allow you to search through the json string easily as such:
JObject myObject = JObject.Parse(json);
var results = myObject["data"]["values"]["page views"].First();
Edit:
Since your Json contains keys, which begin with a number (and are not valid c# variable names) its a bit more tricky but doable. The automatic converter failed on this.
string json = "{\"computed_at\": \"2019 - 11 - 19T10: 36:33.908802 + 00:00\", \"legend_size\": 1, \"data\": {\"series\": [\"2019 - 11 - 11\", \"2019 - 11 - 12\", \"2019 - 11 - 13\"], \"values\": {\"page views\": {\"2019 - 11 - 12\": 111, \"2019 - 11 - 11\": 573, \"2019 - 11 - 13\": 209}}}}";
var myObject = JsonConvert.DeserializeObject<RootObject>(json);
foreach (var view in myObject.data.series)
{
int number = myObject.data.values.page_views[view];
Console.WriteLine($"{number} views on {view}");
}
With the RootObject class being:
public class Values
{
[JsonProperty("page views")]
public Dictionary<string, int> page_views { get; set; }
}
public class Data
{
public List<string> series { get; set; }
public Values values { get; set; }
}
public class RootObject
{
public string computed_at { get; set; }
public int legend_size { get; set; }
public Data data { get; set; }
}
The trick was to use a Dictionary<string, int> type for the date-values, and rename the property to a valid c# name. The JsonDeserializer still finds the data, because we told it to look for "page views" using the JsonProperty attribute. This way the class is also flexible for multiple entries in your "page views" field.
Hope this helps
You were close. In the line
var rawData = result["data"]["values"]["page views"][0]
you are attempting to access index 0 of an object. This doesn't really make sense because objects are basically dictionaries or hash tables, which means they are unordered and must be accessed by a key rather than an index (See Retrieving a property of a JSON object by index?).
What you want looks like
var rawData = result["data"]["values"]["page views"]['2019-11-12'] to access the number of page views (which is 111) for the date 2019-11-12.
You can then loop through the object and get each number of page views as follows:
var pageViews = [];
for (var key of Object.keys(result.data.values['page views'])) {
pageViews.push(result.data.values['page views'][key]);
}

C# JSON deserialize same object that acts like an array without being an array

I feel like I'm making this much harder than it needs to be.
In C# using Netwonsoft JSON Compact with external data. Trying to figure out how to deserialize/parse data that looks like
{"http":{"0":{"title":"arbitrary","value":"arbitrary"},"1":{"title":"arbitrary","value":"arbitrary"}},"sip":{"1003":{"title":"arbitrary","value":"none"}}}
It's essentially an array of notifications and the ID -- "0", "1", and "1003" in the above examples is an arbitrary value and appears to have a valid range of 0 and roughly 65535.
But it's not formatted as an array (or I wouldn't be here) -- need help figuring out how to deserialize the value object while essentially ignoring the string identifier.
Thanks in advance
You can't easily deserialize it as an array, but you can deserialize it to a dictionary with integer keys. I don't know about Json.NET Compact, but this works fine with regular Json.NET:
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
class Root
{
public Dictionary<int, Property> Http { get; set; }
public Dictionary<int, Property> Sip { get; set; }
}
class Property
{
public string Title { get; set; }
public string Value { get; set; }
}
class Test
{
static void Main()
{
string json = File.ReadAllText("test.json");
var root = JsonConvert.DeserializeObject<Root>(json);
foreach (var entry in root.Http)
{
Console.WriteLine($"{entry.Key}: {entry.Value.Title}/{entry.Value.Value}");
}
}
}
If you really need the properties as arrays, I'd suggest having two separate classes: one for the JSON representation, and then another for real usage. For example:
class RootJson
{
public Dictionary<int, Property> Http { get; set; }
public Dictionary<int, Property> Sip { get; set; }
}
class Root
{
// TODO: Control access more :)
public Property[] Http { get; set; }
public Property[] Sip { get; set; }
}
Then:
var rootJson = ...;
var root = new Root
{
Http = rootJson.Http.Values.ToArray(),
Sip = rootJson.Sip.Values.ToArray(),
};
If you can't change the structure of the JSON, you can always do something like this. The dynamic type figures out what to do on runtime.
dynamic d = JsonConvert.DeserializeObject("{'http':{'0':{'title':'arbitrary','value':'arbitrary'},'1':{'title':'arbitrary','value':'arbitrary'}},'sip':{'1003':{'title':'arbitrary','value':'none'}}}");
Console.WriteLine(d.http["0"].title); // arbitrary
foreach(var prop in d.http) {
Console.WriteLine(prop);
}
foreach(var prop in d.sip) {
Console.WriteLine(prop);
}
Final output:
arbitrary
"0": {
"title": "arbitrary",
"value": "arbitrary"
}
"1": {
"title": "arbitrary",
"value": "arbitrary"
}
"1003": {
"title": "arbitrary",
"value": "none"
}

Querying JSON using SelectTokens? With Newtonsoft.Json.Linq in C#

I'm trying to make use of Netwonsoft.JSON.Linq in C#, to change the "statusCode" values in the following JSON:
{
"disbursements":[
{
"id":"1f337641",
"contactId":"f5eb2",
"statusCode":166000005,
"amount":8,
"category":166000001
},
{
"id":"027a4762",
"contactId":"f5eb2038",
"statusCode":166000000,
"amount":4000,
"category":166000000
}
]
}
So, inside the JSON data is: "disbursements" which is JSON array. I have to change the "statusCode" of each item in the array to 166000005. I'm able to retrieve statusCode of the first one using
JObject jsonText = JObject.Parse(bodyText);
var statusCode = (int)jsonText.SelectToken("disbursements[0].statusCode");
But I need a solution with loop or LINQ that changes all the values, not just the first.
The following code sets or adds "statusCode": 166000005 to every entry in the disbursement array:
var jsonText = JObject.Parse(bodyText);
foreach (var disbursement in jsonText.SelectTokens("disbursements[*]"))
{
disbursement["statusCode"] = 166000005;
}
Notes:
The query string "disbursements[*]" contains the JSONPath wildcard operator [*]. This operator matches all array elements under the parent element "disbursement".
Json.NET supports JSONPath syntax as documented in Querying JSON with JSONPath.
SelectTokens() is used rather than SelectToken() to loop through multiple possible matches.
The JToken item setter disbursement["statusCode"] = 166000005 will replace the "statusCode" property if present and add it if not.
A simple, atomic value such as 166000005 can be set directly into a JToken hierarchy. For a complex POCO you would need to call JToken.FromObject() to serialize it to a JToken before setting it in the hierarchy, e.g.:
disbursement["statusCode"] =
JToken.FromObject( new { oldValue = disbursement["statusCode"], newValue = 166000005 } );
Sample working .Net fiddle.
I would create classes to represent the data. Here is my solution:
Create the data holder classes:
public class Disbursement
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("contactId")]
public string ContactId { get; set; }
[JsonProperty("statusCode")]
public int StatusCode { get; set; }
[JsonProperty("amount")]
public int Amount { get; set; }
[JsonProperty("category")]
public int Category { get; set; }
}
The collection:
public class Disbursements
{
[JsonProperty("disbursements")]
public List<Disbursement> Items { get; set; } = new List<Disbursement>();
}
And then the loading / modifying / saving data:
class Program
{
static void Main(string[] args)
{
var disbursements =
JsonConvert.DeserializeObject<Disbursements>(
File.ReadAllText(
"data.json",
Encoding.UTF8
)
);
foreach (var disbursement in disbursements.Items)
{
disbursement.StatusCode = 166000005;
}
string modifiedContent = JsonConvert.SerializeObject(disbursements);
File.WriteAllText(
"modifiedData.json",
modifiedContent,
Encoding.UTF8
);
}
}

Deserializing JSON collection in C#

This is a JSON message I get from server (which I can't change). There might be many more objects (time / value) returned, but in this case there is only one. The format stays the same regardless.
{
"data": [
{
"time": "2014-12-12T13:52:43",
"value": 255.0
}
]
}
I'm trying to deserialize the JSON to a very simple C# object.
public class Dataentry {
public float Value { get; set; }
public DateTime Time { get; set; }
}
I've tried deserialization with Newtonsoft's JSON.Net and RestSharp libraries with no success. The following code doesn't work, but neither does anything else I've tried :-) I get no error -- just an empty object with default initial values.
var myObject = JsonConvert.DeserializeObject<Dataentry> (jsonString);
Since those libraries are not very intuitive or well documented in this kind of case, I'm lost. Is this kind of JSON impossible to deserialize? I really would like to use a ready-made library, so any help would be appreciated.
This is not working because your JSON is specifying a collection and you are trying to deseralize into one object. There are plenty of json to c# class generators you can paste json into to get an appropriate class definition(s) one such generator is located here
A more appropriate definition would be
public class Datum
{
public string time { get; set; }
public double value { get; set; }
}
public class RootObject
{
public List<Datum> data { get; set; }
}
Then deseralize as
var myObject = JsonConvert.DeserializeObject<RootObject> (jsonString);
I'd like add some extra explanetion to your question...
You write I'm trying to deserialize the JSON to a very simple C# object. - unfortunatelly this is not the complete truth. What you are trying is to deserialize a collection of a very simple C# objects. The indicator for this are the square brackets in your json:
{
"data": [
{
"time": "2014-12-12T13:52:43",
"value": 255.0
}
]
}
It means that there is a class with a property named data (it can ba mapped to some other name but for the sake of simplicity let's stick to this name) and that this property is a collection type. It can be one of any types that support the IEnumerable interface.
public class DataCollection
{
public DataItem[] data { get; set; }
//public List<DataItem> data { get; set; } // This would also work.
//public HashSet<DataItem> data { get; set; } // This would work too.
}
public class DataItem
{
public float value { get; set; }
public DateTime time { get; set; } // This would work because the time is in an ISO format I believe so json.net can parse it into DateTime.
}
The next step is to tell Json.Net how to deserialize it. Now when you know it's a complex data type you can use the type that describes the json structure for deserialization:
var dataCollection = JsonConvert.DeserializeObject<DataCollection>(jsonString);
If you didn't have the data property in you json string but something like this:
[
{
"time": "2014-12-12T13:52:43",
"value": 255.0
},
{
"time": "2016-12-12T13:52:43",
"value": 25.0
},
]
you could directly deserialize it as a collection:
var dataItems = JsonConvert.DeserializeObject<List<DataItem>>(jsonString);
or
var dataItems = JsonConvert.DeserializeObject<DataItem[]>(jsonString);
change your DateEntry binding Definition
public class ArrayData{
public DataEntry data {set; get;}
}
public class DataEntry {
public float Value { get; set; }
public DateTime Time { get; set; }
}
in your method now you can received an ArraData Object
be careful with datetime string values sent for correct binding

Categories

Resources