Parsing Json with nested and variable dictionaries using Newtonsoft [duplicate] - c#

This question already has an answer here:
How to deserialize a JSON property that can be two different data types using Json.NET
(1 answer)
Closed 1 year ago.
I have a Json that looks as this:
{
"id": "1367",
"title": "ticket sample",
"custom_fields": {
"13084": {
"E0D4ED43": "South"
},
"13085": {
"F19DF0D6": "Atlanta"
},
"13089": {
"AF0EC62F": "Peter Johnson"
}
}
}
And to parse it, my class uses nested Dictionaries:
class incident
{
public string id { get; set; }
public string title { get; set; }
public Dictionary<int, Dictionary<string, string>> custom_fields { get; set; }
}
This works like a charme, until I've discovered that the custom fields are not always the same, for example I could receive:
{
"id": "1367",
"title": "ticket sample",
"custom_fields": {
"13084": {
"E0D4ED43": "South"
},
"13085": {
"F19DF0D6": "Atlanta"
},
"13086": "SAP",
"13088": {
"AE3ED01A": "Commercial"
}
}
}
If you look at the custom field "13086", it doesn't contains another object (it's just a string), so when I try to parse with the previous class it fails.
Those are examples of two different responses, but the keys received change a lot (that's why I used Dictionaries because I don't know how many and which will be received for each ticket)

Thank you all guys for your comments. Thanks to them I figured it out and found a solution that works for me.
Basically, I've used the "Dictionary<int, object>" proposed by #DilshodK and then I check for the type of the object. If the object is a JObject I re-deserialize with another Dictionary, if not I use the original value.
class incident_custom
{
public string id{ get; set; }
public string title { get; set; }
public Dictionary<int, object> custom_fields { get; set; }
}
incident_custom item = JsonConvert.DeserializeObject<incident_custom>(responseBody);
Console.WriteLine(item.title);
foreach (var field in item.custom_fields)
{
if (field.Value.GetType() == typeof(Newtonsoft.Json.Linq.JObject))
{
Dictionary<string, object> values = JsonConvert.DeserializeObject<Dictionary<string, object>>(field.Value.ToString());
foreach (var value in values)
{
Console.WriteLine(field.Key + " - " + value.Value);
}
}
else
{
Console.WriteLine(field.Key + " - " + field.Value);
}
}

Related

querying dynamic json using c#

We have the following Json
{
"#message": "some message",
"outputs": {
"outone": {
"value": "eastus2"
},
"outtwo": {
"value": "r7ty-network"
}
}
}
the outputs section contain 2 objects "outone" and "outtwo", we are struggling to get hold of the the names "outone" and "outtwo" and its corresponding value property.
we generated c# classes and everything was working as expected, but later we were told that the values "outone" and "outtwo",are dynamic, they can be named anything.
any pointers will help.
Thanks -Nen
try this code using Newtonsoft.Json
var jsonDeserialized= JsonConvert.DeserializeObject<Data>(json);
and classes
public partial class Data
{
[JsonProperty("#message")]
public string Message { get; set; }
[JsonProperty("outputs")]
public Dictionary<string,Out> Outputs { get; set; }
}
public partial class Out
{
[JsonProperty("value")]
public string Value { get; set; }
}
I assume you want to have some kind of key value list. Here's a demo in form of a test that's green:
UPDATE: Took care of eventual duplicate "keys"
[TestMethod]
public void JObject_Test()
{
var jObject = JObject.Parse(
#"{
""#message"": ""some message"",
""outputs"": {
""outone"": {
""value"": ""eastus2""
},
""outtwo"": {
""value"": ""r7ty-network""
}
}
}");
var outputs = new List<KeyValuePair<string, string>>();
foreach (var jproperty in jObject["outputs"].Children<JProperty>())
{
outputs.Add(
new KeyValuePair<string, string>(jproperty.Name,
(string)((JObject)jproperty.Value)["value"]));
}
Assert.AreEqual("outone", outputs[0].Key);
Assert.AreEqual("eastus2", outputs[0].Value);
Assert.AreEqual("outtwo", outputs[1].Key);
Assert.AreEqual("r7ty-network", outputs[1].Value);
}

Compare JSON array and JSON object: Cannot convert Array to String error

I am trying to compare json value and based on that i want to update the existing value,for example, currently we have "value" : [r0] in json, i want to compare and if value : [r0] ,then update it to [r0,r1] but iam hiting error that it cannot compare and there is a cast issue, could someone suggest what could be done
public void updateJsonParameter(string file)
{
try
{
var list = new List<string> { "joe", "test" };
JArray array = new JArray(list);
var jobject = JObject.Parse(file);
var ringvalue = (string)jobject["properties"]["parameters"]["ringValue"]["value"]; // unable to case here and compare
jobject["properties"]["parameters"]["ringValue"]["value"] = array; // able to update value but i want to update after comparing the existing values
var result = JsonConvert.SerializeObject(jobject);
}
following is the json format
{
"properties": {
"displayName": "jayatestdefid",
"description": "test assignment through API",
"metadata": {
"assignedBy": "xyz#gmail.com"
},
"policyDefinitionId": "/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test",
"parameters": {
"ringValue": {
"value": ["r0"]
}
},
"enforcementMode": "DoNotEnforce",
}
}
jobject.properties.parameters.ringValue.value is an array ["r0"] with one element "r0". If you want to check if it's an array with one element and that element is "r0", do exactly that:
var ringvalue = jobject["properties"]["parameters"]["ringValue"]["value"];
if(ringvalue.length == 1 && ringvalue[0] == "r0")
jobject["properties"]["parameters"]["ringValue"]["value"] = array;
You could compare the ringvalue (which is an JArray) using JArray.DeepEquals and then replace if the comparison returns true. For example,
var list = new List<string> { "joe", "test" };
JArray array = new JArray(list);
JArray valueToCompare = new JArray(new[]{"r0"});
var ringvalue = (JArray)jobject["properties"]["parameters"]["ringValue"]["value"];
if(JArray.DeepEquals(ringvalue,valueToCompare))
{
jobject["properties"]["parameters"]["ringValue"]["value"] = array;
}
First, as Klaycon said in his answer, it's worth noting that your "value" is not a single string. In json, whenever you see [ and ] then you have a collection, or an array, or a list.
When I work with json strings, I always like to be able to convert them into a strongly typed object. There is a very handy online tool I use all the time: http://json2csharp.com/
I took your json string that you provided and pasted it into that website. Here is that your object(s) look like when converted into c# classes:
public class RootObject // You can name this whatever you want
{
public Properties properties { get; set; }
}
public class Metadata
{
public string assignedBy { get; set; }
}
public class RingValue
{
public List<string> value { get; set; }
}
public class Parameters
{
public RingValue ringValue { get; set; }
}
public class Properties
{
public string displayName { get; set; }
public string description { get; set; }
public Metadata metadata { get; set; }
public string policyDefinitionId { get; set; }
public Parameters parameters { get; set; }
public string enforcementMode { get; set; }
}
Now, we can easily do the logic you need as follows:
// This is your json string, escaped and turned into a single string:
string file = "{ \"properties\": { \"displayName\": \"jayatestdefid\", \"description\": \"test assignment through API\", \"metadata\": { \"assignedBy\": \"xyz#gmail.com\" }, \"policyDefinitionId\": \"/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test\", \"parameters\": { \"ringValue\": { \"value\": [\"r0\"] } }, \"enforcementMode\": \"DoNotEnforce\", }}";
// Convert your json string into an instance of the RootObject class
RootObject jobject = JsonConvert.DeserializeObject<RootObject>(file);
// Get a list of all the "values"
List<string> values = jobject.properties.parameters.ringValue.value;
// Loop over your colleciton of "value" and do your logic
for (int i = 0; i < values.Count; ++i)
{
if (values[i] == "r0")
{
values[i] = "r0,r1";
}
}
// And finally, turn your object back into a json string
var result = JsonConvert.SerializeObject(jobject);
And this is the final result:
{
"properties":{
"displayName":"jayatestdefid",
"description":"test assignment through API",
"metadata":{
"assignedBy":"xyz#gmail.com"
},
"policyDefinitionId":"/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test",
"parameters":{
"ringValue":{
"value":[
"r0,r1"
]
}
},
"enforcementMode":"DoNotEnforce"
}
}

JSON Array to Array List using c#

I'm trying to convert JSON to list, please anyone can help me.
public class User
{
public String id { get; set; }
public String imageURL { get; set; }
public String search { get; set; }
public String status { get; set; }
public String username { get; set; }
}
List<User> users = JsonConvert.DeserializeObject<List<User>>(resp.Body);
JSON
{
"KfWE8S9jWJdWnAZEbOtHTtisNwO2":
{"id":"KfWE8S9jWJdWnAZEbOtHTtisNwO2"
,"imageURL":"https://firebasestorage.googleapis.com/v0/b/bchat-af5e5.appspot.com/o/uploads%2F1542785437375.jpg?alt=media&token=be1ce806-fecf-4081-9dad-f0a20e5d8489"
,"search":"rene vizconde"
,"status":"online"
,"username":"Rene Vizconde"},
"ScpDnyQCyKemXSgdo3jEvZFNxY83":
{"id":"ScpDnyQCyKemXSgdo3jEvZFNxY83"
,"imageURL":"default"
,"search":"yeli potpot"
,"status":"offline"
,"username":"Yeli Potpot"},
"cnPYOdHYWaaLDQmchELLvw85DBf1":
{"id":"cnPYOdHYWaaLDQmchELLvw85DBf1"
,"imageURL":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSHilM1ke9pZePBJTobMTcktggiw-UywdqAIpf-VX9nqecKl6b4wQ"
,"search":"bards disc"
,"status":"offline"
,"username":"Bards Disc"},
"tWTbllTxaVM9WQnsNwnBgc3ixLM2":
{"id":"tWTbllTxaVM9WQnsNwnBgc3ixLM2"
,"imageURL":"default"
,"search":"renz angelo"
,"status":"offline"
,"username":"Renz Angelo"}
}
You can simply deserialize your json into Dictionary<string, User> instead of List<User>.
class Program
{
static void Main(string[] args)
{
var data = JsonConvert.DeserializeObject<Dictionary<string, User>>(resp.Body);
foreach (var item in data)
{
User user = item.Value;
Console.WriteLine("id: " + user.id);
Console.WriteLine("imageURL: " + user.imageURL);
Console.WriteLine("search: " + user.search);
Console.WriteLine("status: " + user.status);
Console.WriteLine("username: " + user.username);
Console.WriteLine();
}
Console.ReadLine();
}
}
Output:
There is something wrong in your JSON. Altough its structure is "syntaxly" correct, it was badly designed.
You're naming member of the JSON using ids, and then refers to that ID in each object of thoses members.
Don't Repeat Yourself.
Since the name of the members are dynamic, you can't use that root object to deserialize the JSON. (which is NOT a List<User>, there is no list in that JSON, but objects)
Consider using this structure rather (notice the brackets to create an array of objects)
[
{
"id":"KfWE8S9jWJdWnAZEbOtHTtisNwO2"
,"imageURL":"https://firebasestorage.googleapis.com/v0/b/bchat-af5e5.appspot.com/o/uploads%2F1542785437375.jpg?alt=media&token=be1ce806-fecf-4081-9dad-f0a20e5d8489"
,"search":"rene vizconde"
,"status":"online"
,"username":"Rene Vizconde"
},
{
"id":"ScpDnyQCyKemXSgdo3jEvZFNxY83"
,"imageURL":"default"
,"search":"yeli potpot"
,"status":"offline"
,"username":"Yeli Potpot"
},
{
"id":"cnPYOdHYWaaLDQmchELLvw85DBf1"
,"imageURL":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSHilM1ke9pZePBJTobMTcktggiw-UywdqAIpf-VX9nqecKl6b4wQ"
,"search":"bards disc"
,"status":"offline"
,"username":"Bards Disc"
},
{
"id":"tWTbllTxaVM9WQnsNwnBgc3ixLM2"
,"imageURL":"default"
,"search":"renz angelo"
,"status":"offline"
,"username":"Renz Angelo"
}
]

Extract array from JSON object containing multiple types

(Just a heads up, I'm very new to C#)
(See sample code and JSON structure below)
I can't figure out how to pull "data" out of the JSON reponse and put it into a data table. The variable "response" is just raw JSON data. So far I've figured out how to parse the JSON into a JObject...so now it has two members (data, meta). Now I'm trying to figure out how to get joTest["data"] into a DataTable. The handful of attempts I've made, keep giving me an error when it sees the "meta" member. Maybe I shouldn't be using a Data Table?
Also, in case it changes anything, I don't need the "links" from the "data" members.
I've tried searching for "Converting JObject into Data Table" But I'm not finding a lot of useful results.
public void PerformFeed()
{
string response;
response = Blah.SendMessage().Result;
JObject joTest = JsonConvert.DeserializeObject<JObject>(response);
}
Json Data Structure
{
"data": [
{
"Val1": "1234",
"Val2": "foo1",
"Val3": "bar1",
"links": [
{
"rel": "self",
"uri": "/blah/1234"
},
{
"rel": "pricing_data",
"uri": "/blah/1234/pricing_data"
}
]
},
{
"Val1": "5678",
"Val2": "foo2",
"Val3": "bar2",
"links": [
{
"rel": "self",
"uri": "/blah/5678"
},
{
"rel": "pricing_data",
"uri": "/blah/5678/pricing_data"
}
]
}
],
"meta": {
"pagination": {
"total": 2,
"count": 2,
"per_page": 25,
"current_page": 1,
"total_pages": 1,
"links": []
}
}
}
UPDATE: I've figured out a "solution" but I really don't think it's a good solution. I built a datatable and then used a foreach statement on the JObject to populate the data table that way. It seems very inefficient...but for now it works. Hopefully I'll find a better way.
public void PerformFeed()
{
DataTable Items = new DataTable();
Items.Columns.Add("Val1");
Items.Columns.Add("Val2");
Items.Columns.Add("Val3");
string response = Blah.SendMessage().Result;
JObject Data = JObject.Parse(response);
foreach (JObject jo in Data["data"])
{
Items.Rows.Add(jo["Val1"], jo["Val2"], jo["Val3"]);
}
}
There is this really nice online utility that helps extracting C# classes from JSON objects. I think the problem here is with your JSON, you're missing a comma ",". You would easily be able to spot the error with some online JSON formatter / validator. Rest the deserialization is pretty straightforward. Try the following:
JObject obtainedObject = JObject.Parse(JsonString);
Following would be the structure of your obtained object:
public class RequiredClass
{
public IList<Datum> data { get; set; }
public Meta meta { get; set; }
}
public class Datum
{
public string Val1 { get; set; }
public string Val2 { get; set; }
public string Val3 { get; set; }
public IList<Link> links { get; set; }
}
public class Link
{
public string rel { get; set; }
public string uri { get; set; }
}
public class Pagination
{
public int total { get; set; }
public int count { get; set; }
public int per_page { get; set; }
public int current_page { get; set; }
public int total_pages { get; set; }
public IList<object> links { get; set; }
}
public class Meta
{
public Pagination pagination { get; set; }
}
Update:
Here's is how you extract your array and convert that to a DataTable:
JObject jObject = JObject.Parse(json);
JToken dataArray = jObject["data"];
DataTable dt = (DataTable) JsonConvert.DeserializeObject(dataArray.ToString(), (typeof(DataTable)));
To avoid the surplus casting, you can try the following using the class structure already mentioned above:
JObject jObject = JObject.Parse(json);
JToken dataArray = jObject["data"];
List<Datum> requiredList = new List<Datum>();
foreach (var item in dataArray)
{
Datum obj = new Datum();
obj.Val1 = (string) item["Val1"] ?? "";
obj.Val2 = (string) item["Val2"] ?? "";
obj.Val3 = (string) item["Val3"] ?? "";
obj.links = new List<Link>();
foreach(var subItem in item["links"])
{
Link lnk = new Link();
lnk.rel = (string) subItem["rel"] ?? "";
lnk.uri = (string) subItem["uri"] ?? "";
obj.links.Add(lnk);
}
requiredList.Add(obj);
}

c# Converting json string with list of objects to a c# object

I'm tring to convert a string json to c# object,
I've already read several replies in here regarding to similar questions but none of the solutions worked.
This is the json obj
{
"Customer": {
"data_0": {
"id": "273714",
"FirstName": "Zuzana",
"LastName": "Martinkova"
},
"data_1": {
"id": "274581",
"FirstName": "Ricardo",
"LastName": "Lambrechts"
},
"data_2": {
"id": "275190",
"FirstName": "Daniel",
"LastName": "Mojapelo"
},
"data_3": {
"id": "278031",
"FirstName": "Sulochana",
"LastName": "Chandran"
}
}
}
I created the following objects according to the json obj
public class Customer
{
public List<Data> Customers{ get; set; }
public Customer()
{
Customers = new List<Data>();
}
}
public class Data
{
public string id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
As for my code I made a small console app example with all the solotions I found here
static void Main(string[] args)
{
try
{
string jsonString = File.ReadAllText(ConfigurationSettings.AppSettings["filepath"].ToString());
//solution 1
JObject jsonone = JObject.Parse(jsonString);
var collection_one = jsonone.ToObject<Customer>();
//solution 2
JavaScriptSerializer serializer = new JavaScriptSerializer();
var collection_two = serializer.Deserialize<Customer>(jsonString);
//solution 2
var collection_three = JsonConvert.DeserializeObject<Customer> (jsonString);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); ;
}
Console.ReadKey();
}
Ths json string I get from a 3rd party webservice so just for the example I'm reading the json from a txt file,
the jsonString param value after reading is:
"{\"Customer\":{\"data_0\":{\"id\":\"273714\",\"FirstName\":\"Zuzana\",\"LastName\":\"Martinkova\"},\"data_1\":{\"id\":\"274581\",\"FirstName\":\"Ricardo\",\"LastName\":\"Lambrechts\"},\"data_2\":{\"id\":\"275190\",\"FirstName\":\"Daniel\",\"LastName\":\"Mojapelo\"},\"data_3\":{\"id\":\"278031\",\"FirstName\":\"Sulochana\",\"LastName\":\"Chandran\"}}}"
On every solution I make the collections count is 0, data objects are not including inside the list.
Can someone put some light on it and tell me what is wrong?
Thanks in advance
Your JSON is a Dictionary<string, Data>, not a List<Data>. In addition to that your property is called "Customer", not "Customers". To solve this you need to change a couple things:
public class Customer
{
//JsonProperty is Used to serialize as a different property then your property name
[JsonProperty(PropertyName = "Customer")]
public Dictionary<string, Data> CustomerDictionary { get; set; }
}
public class Data
{
public string Id { get; set; } //You should make this "Id" not "id"
public string FirstName { get; set; }
public string LastName { get; set; }
}
With these class definitions you can easily use the JsonConvert.DeserializeObject() and JsonConvert.SerializeObject() methods:
Customer customer = JsonConvert.DeserializeObject<Customer>(json);
string newJson = JsonConvert.SerializeObject(customer);
I made a fiddle here to demonstrate.
You can try this one.
Add empty class
public class Customer : Dictionary<string, Data>{} //empty class
And the update your existing code
//solution 1
JObject jsonone = JObject.Parse(jsonString);
//Add this line
var token = jsonone.SelectToken("Customer").ToString();
//solution 2 - update jsonString to token variable created above.
var collection_three = JsonConvert.DeserializeObject<Customer>(token);

Categories

Resources