Deserialize a generic JSON and use its properties - c#

I need to call an API that returns a JSON that can vary.
Sometimes the response could be something like:
[
{
"name": "value"
}
]
while other times
[
{
"property": "value"
}
]
or even
[
{
"name": "value",
"status": "value",
"count": "value"
}
]
Basically, I need to retrieve all values in this JSON for later use.
I tried
var prova = JsonConvert.DeserializeObject<dynamic>(result);, but I can't access the properties using ["indexName"] because the index can vary depending on some factors. Any ideas?

You can create a POCO that that has all the possible properties if they are finite. Like the following :
public class Result {
public string name { get; set; }
public string property { get; set; }
public string status { get; set; }
public string count{ get; set; }
}
And then you can use: var prova = JsonConvert.DeserializeObject<IEnumerable<Result>>(Result);. I change the deserialization to using an IEnumerable because I see that your JSON is an array.
And then you can check if the values are null before accessing them. Since every Result object will only have the property that was available in JSON as non-null.
Alternatively, you can use a Dictionary<string, string> or Dictionary<string, int> and do the following :
var prova = JsonSerializer.Deserialize<IEnumerable<Dictionary<string, string>>>(result) as List<Dictionary<string, string>>;
and then you can access every object of the list and access the property you want like this or TryGetValue Method for more safety.
Console.WriteLine(prova[0]["name"]);

Assumption:
You're getting an array of objects from the api (that doesn't return null data - re: probably why the structure is "dynamic").
Here's one way:
//System.Text.Json
var foo = JsonSerializer.Deserialize<JsonElement>(array_from_api);
//It's an array (assumption) of one or more objects
foreach (JsonElement element in foo.EnumerateArray())
{
//iterate through each object's properties
foreach (JsonProperty o in element.EnumerateObject())
{
//Assumption: value isn't a nested object/array, otherwise adjust...
Console.WriteLine($"{o.Name} = {o.Value}");
}
}
//Json.Net
//It's an array (assumption) of one or more objects
JArray deserialized = JsonConvert.DeserializeObject<JArray>(array_from_api);
foreach (JObject jo in deserialized)
{
//iterate through each JObject's properties
foreach (JProperty p in jo.Properties())
{
Console.WriteLine($"{p.Name} = {p.Value}");
}
}
Note: If the structure is more complex - more nesting, you'll have to do some checks and adjust accordingly (re: nested arrays, objects, etc)

Related

JSON.NET Deserializing a JSON into a dictionary comes back as null

I have this JSON:
{
"AAPL": { "price": "131.85000" },
"eur/usd": { "price": "1.06290" },
"msft": { "price": "238.76000" }
}
When I try to deserialize this into a dictionary it comes back as null.
I am using the TwelveDataAPI.
https://twelvedata.com/docs#real-time-price
I have tried creating a simple class that will allow me to deserialize this JSON even if there are different tickers and different amounts of them.
My class:
public class CurrentPriceClass
{
public class Root
{
public Dictionary<string, Price> Prices { get; set; }
}
public class Price
{
public string price { get; set; }
}
}
But when I try to deserialize it, it comes back as null, and I cannot iterate over it:
CurrentPriceClass.Root priceRoot = JsonConvert.DeserializeObject<CurrentPriceClass.Root>(
dataJson);
foreach (KeyValuePair<string, CurrentPriceClass.Price> price in priceRoot.Prices)
{
Console.WriteLine($"{price.Key}: {price.Value.price}");
}
The error I get when iterating is:
Object reference not set to an instance of an object.
When debugging priceRoot is null.
I am assuming that this is a problem with my class.
Deserialize as Dictionary<string, CurrentPriceClass.Price> without needing the root class (CurrentPriceClass).
Dictionary<string, CurrentPriceClass.Price> priceRoot = JsonConvert.DeserializeObject<Dictionary<string, CurrentPriceClass.Price>>(dataJson);
foreach (KeyValuePair<string, CurrentPriceClass.Price> price in priceRoot)
{
Console.WriteLine($"{price.Key}: {price.Value.price}");
}
Demo # .NET Fiddle

C# Iterate over a JSON object

I'm trying to use the .Net Json deserializer System.Text.Json to iterate over the following Json input.
I've found methods for iterating by "person_id" if it were the top level in the json structure (see below), but I haven't been able to track down a method for looping through all of the next level items.
I think the NewtonSoft JArray and JObject are pretty close to what I need (I may pursue that) but wasn't sure if Microsofts solution had a way to do it...
Is this possible with Microsoft's System.Text.Json library?
{
"0": {
"person_id": "0",
"last_name": "Greg",
"first_name": "Craig",
},
"1": {
"person_id": "1",
"last_name": "Doe",
"first_name": "John",
}
}
JsonElement solution for extracting an object by property name (ie I can get John Doe's information this way).
using (JsonDocument document = JsonDocument.Parse(jsonString))
{
JsonElement root = document.RootElement;
JsonElement studentsElement = root.GetProperty("1");
}
Looks similar to some JSON I've had to tackle before. It helps to remember that JSON objects are just key/value pairs.
With this in mind, the data structure you have could be interpreted as a Dictionary in C#.
I've used Newtonsoft.Json in my examples, but they are easy to swap over to use System.Text.Json.
In its simplest form, you could use:
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonString);
Which will give you a Dictionary where the key is the "0", "1" properties, and the value is the object representing the person info inside.
You can then run a simple foreach loop over the Dictionary, or its keys, or values, like so:
foreach (var item in dictionary)
{
var key = item.Key;
var person = item.Value;
}
But the person (item.Value) is still only of type object.
This is where you can create a class to represent each Person's info, decorating the properties to match what's in the JSON data structure, like so:
public class Person
{
[JsonProperty("person_id")]
public string PersonId { get; set; }
[JsonProperty("first_name")]
public string FirstName { get; set; }
[JsonProperty("last_name")]
public string LastName { get; set; }
}
and instead deserialize your JSON to a Dictionary<string, Person>:
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, Person>>(jsonString);
Which means each value of the entry in the dictionary is an instance of Person, and you can access the strongly-typed properties of each, like so:
foreach (var item in dictionary)
{
var key = item.Key; // although you probably won't need this
Console.WriteLine(key);
var person = item.Value;
Console.WriteLine(person.PersonId);
Console.WriteLine(person.FirstName);
Console.WriteLine(person.LastName);
}
// which gives the following output:
> 0
> 0
> Craig
> Greg
> 1
> 1
> John
> Doe
Although I've used Newtonsoft.Json above, it's easy to "migrate" the above sample to use System.Text.Json.
Instead of JsonConvert.DeserializeObject<T>, use JsonSerializer.Deserialize<T>; and
Instead of using [JsonProperty("property_name")] attribute, you can use [JsonPropertyName("property_name")].
Hope this helps.
You can use JsonElement.EnumerateObject. It is used to enumerate the properties in the JSON object represented by this JsonElement
var options = new JsonDocumentOptions
{
AllowTrailingCommas = true,
CommentHandling = JsonCommentHandling.Skip
};
using (JsonDocument document = JsonDocument.Parse(jsos, options))
{
foreach (JsonProperty property in document.RootElement.EnumerateObject())
{
string key = property.Name;
JsonElement valueElement = property.Value;
string person_id = valueElement.GetProperty("person_id").GetString();
string last_name = valueElement.GetProperty("last_name").GetString();
string first_name = valueElement.GetProperty("first_name").GetString();
}
}

Sort object by property in JObject

I have a list defined as:
List<SensorData> tempSensorData = new List<SensorData>();
This is how I am populating this list:
tempSensorData.Add(new SensorData
{
Data = JObject.Parse(values[r, 4].ToString()),
SensorGuid = values[r, 2].ToString()
});
This is my definition of SensorData class:
public class SensorData
{
public JObject Data { get; set; }
public string SensorGuid { get; set; }
}
There is a property in Data Property called timestamp. I want my list to be sorted by that value. How can I do that?
I have tried doing:
tempSensorData.OrderBy(o => o.Data.SelectToken("timestamp"));
But it doesn't help
This is the JSON value in Data:
{{
"Record": "A",
"timestamp": 1572987031,
"signal_strength": "021",
"vbatt": "3.10",
"temperature": "21.5"
}}
You can try something like that
var result = tempSensorData.OrderBy(o => o.Data["timestamp"].Value<long>());
Get a long value of timestamp property using Value<T> method of JToken, then use this value in a Func<TSource,TKey> key selector in OrderBy.
Unlike Sort method of List<T> class, OrderBy method returns an IOrderedEnumerable as a result instead of changing a source list, so you should assign return value to the variable

What is the correct way to parse this JSON object in C#?

This is the JSON object I am receiving from a GET request:
{
"data": {
"valve_maker": [],
"water_volume": [
"15L",
"20L",
"..."
],
"cylinder_manufacturer": [
"Tianhai"
],
"qc_stamp": [
"TS"
],
"reference_standard": [
"GB 5099"
],
"production_licence": [
"TS2210752-2016"
],
"valve_production_licence": [
"TSF210030"
],
"rate_of_residual_deformation": {
"1": "<3%",
"2": "<10%"
},
"material_number": {
"1": "30CrMo",
"2": "34CrMo4",
"3": "..."
},
"heat_treatment": {
"1": "...",
"2": "..."
},
"drawing_number": {
"1": "...",
"2": "..."
},
"cylinder_thickness": []
}
right now, I am able to parse JSON objects with a simpler structure like :
{
"data": [
{
"gas_id": "ID of the gas",
"gas_name": "Gas name"
}
]
by using something like this:
private void jsonparsegas(string res)
{
JObject par = JObject.Parse(res);
foreach (JToken data in par["data"].Children())
{
string id = data["gas_id"].ToString();
string name = data["gas_name"].ToString();
if (this.cmbCylType.Items.Contains(name) == false)
{
this.cmbCylType.Items.Add(name);
}
}
}
When I try to apply the same thing to the more complicated JSON object, I get an error:
private void jsonparsecoc(string res)
{
//JObject par = JObject.Parse(res);
var jObj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(res);
foreach (var child in jObj["data"].Children())
{
string vMaker = child["valve_maker"].ToString(); //error thrown here right away
string wVolume = child["water_volume"].ToString();
string cMan = child["cylinder_manufacturer"].ToString();
string QC = child["qc_stamp"].ToString();
string rStandard = child["reference_standard"].ToString();
string pLicence = child["production_licence"].ToString();
string VPL = child["valve_production_licence"].ToString();
string rrd = child["rate_of_residual_deformation"].ToString();
string mNum = child["material_number"].ToString();
string hTreatment = child["heat_treatment"].ToString();
string dNum = child["drawing_number"].ToString();
string cThick = child["cylinder_thickness"].ToString();
}
Cannot access child value on Newtonsoft.Json.Linq.JProperty
I have tried a few different things I found on StackOverflow, but I don't really understand how Deserializing of the objects works. The simpler parsing works just fine, and allows me to add all "gas_name"s that I receive from my GET request to a combobox. The format the first "valve_maker" child of "data" seems to have the same structure as "gas_id" or "gas_name" in the more similar JSON object, but this is where I receive the error right away. If I had to guess at a cause for the error, I'd say it has something to do with the difference between using
"valve_maker": []
and using
"gas_id": "ID of the gas"
in the objects. also I notice "data" is followed by [] brackets in the simpler one, and {} in the more complicated one.
If anyone could link to some good reading material, or offer a good explanation of a solution/what's going on, I'd really appreciate it.
This part is the key to the problem you're having:
in the objects. also I notice "data" is followed by [] brackets in the simpler one, and {} in the more complicated one.
In JSON,
[] brackets enclose an array
{} brackets enclose an object
In both code examples, you are digging into the object by looping through the results using par["data"].Children(). To be consistent with the JSON model, JSON.NET defines different behavior for resolving children of objects and arrays. The children of an object are its properties and the children of an array are its items.
In your code, the input to jsonparsegas is an array of simple objects with 2 properties where the input to jsonparsecoc is a single complex objects with many properties.
In jsonparsegas, the Children() call gives you an array of all the simple gas objects. You loop through these objects and extract the values of "gas_id" and "gas_name" for each object. In your example data, there only happens to be one gas object so your code only executes once.
In jsonparsecoc, the Children() call actually gives you property values for the properties of the complex object, since the result is an object and not an array. So, when you loop through this result you can't access things like "valve_maker", because they are defined on the complex object and you have already stepped into the value for valve_maker then this executes.
The solution is simple. Don't loop through the properties in jsonparsecoc. Instead of foreach(var child in jObj["data"].Children()) you need something like var child = jObj["data"];. This will give you the reference to the object that actually contains each of the properties you are trying to access.
#smartcaveman did a good job of explaining what is going wrong with your code. However, you might find your data a little easier to process if you defined strongly-typed classes for it like this:
class RootObject
{
public Data Data { get; set; }
}
class Data
{
[JsonProperty("valve_maker")]
public List<string> ValveMaker { get; set; }
[JsonProperty("water_volume")]
public List<string> WaterVolume { get; set; }
[JsonProperty("cylinder_manufacturer")]
public List<string> CylinderManufacturer { get; set; }
[JsonProperty("qc_stamp")]
public List<string> QCStamp { get; set; }
[JsonProperty("reference_standard")]
public List<string> ReferenceStandard { get; set; }
[JsonProperty("production_licence")]
public List<string> ProductionLicense { get; set; }
[JsonProperty("valve_production_licence")]
public List<string> ValveProductionLicense { get; set; }
[JsonProperty("rate_of_residual_deformation")]
public Dictionary<string, string> RateOfResidualDeformation { get; set; }
[JsonProperty("material_number")]
public Dictionary<string, string> MaterialNumber { get; set; }
[JsonProperty("heat_treatment")]
public Dictionary<string, string> HeatTreatment { get; set; }
[JsonProperty("drawing_number")]
public Dictionary<string, string> DrawingNumber { get; set; }
[JsonProperty("cylinder_thickness")]
public List<string> CylinderThickness { get; set; }
}
You can deserialize the JSON to your classes like this:
RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);
Demo here: https://dotnetfiddle.net/p0D7ze
public class Test{
public Data data{get;set;}
}
public class Data{
public List<string> Value_maker{get;set;}
public List<String> Water_Volume{get;set;}
public List<String> cylinder_manufacturer{get;set;}
}
Create Class structure Like that and after that use to deserialize
Jsonconvert.DeserializeObject(JsonString)
it will convert json into proper object, keep in mind structure should be proper and property name should be same as your json property
Hope It will Help you

How do I deserialize this JSON?

How do I deserialize the following JSON with Web API (JSON.Net)?:
{
"action": "edit",
"table": "MainView",
"id": "row_1377",
"_group_id": "999",
"data": {
"ROTATION": "1", // This name/val can change
"EQUIPMENT": [{
"id": "6"
},
{
"id": "8"
}],
"NOTES": ""
}
}
The values in data represent columns and can change, so I can't make a set-in-stone object with e.g. a string named "NOTES" as in json.net deserialize string to nested class.
Notice EQUIPMENT contains multiple values. When it was previously just a "string:string" like NOTES, this JSON deserialized data into a Dictionary<string, string>, but now I need it to behave like its own dictionary. My last attempt was to deserialize into the following type:
public class EditorSubmissionJoined
{
public string _group_id { get; set; }
public string action { get; set; }
public string table { get; set; }
public string id { get; set; }
// "public" added below due to mistake noticed by Maggie Ying
public Dictionary<string, object> data { get; set; } // Trouble
}
I was hoping that the object could contain anything in data whether a KeyValuePair (like NOTES) or a dictionary (like EQUIPMENT).
I've also tried Dictionary<string, ICollection<Object>>, Object, and even ICollection<Dictionary<string, Object>>.
The problem is that my controller always gets EditorSubmissionJoined with nothing but null values:
public void Put(EditorSubmissionJoined ajaxSubmission) {
// ajaxSubmission has only NULL values
}
Try setting your 'data' property to public and your JSON should be able to model bind correctly.
There's a few ways you can do it. One way is to simply use a JObject and access the fields by name e.g. : jsonObject["data"]["ROTATION"]. You can "deserialize" that with JObject.Parse and just "parse" the JSON text into a JObject.
Alternatively you can write your own JsonConverter and tell JSON.net to use that converter when deserializing a specific type (e.g. JsonConverterAttribute). This requires parsing parts of the JSON text manually, in the ReadJson override, and really depends on what data you expect.
You can also use the dynamic approach that Preston commented on.
Which approach you pick depends on how strongly-typed you want things to be.

Categories

Resources