Json to C# object handling dynamic properties - c#

I am trying to implement the json structure in c# objects and I am trying to understand how I can use the correct object depending on the type. For example:
public class RootObject
{
public string name { get; set; }
public Content content { get; set; }
}
public class Content
{
public string id{ get; set; }
public string type { get; set; }
public Dictionary<string, Item> child { get; set; }
}
public class Item
{
public string id { get; set; }
public string type { get; set; }
public List<string> model { get; set;}
public string[] color {get; set;}
}
Please note this is just an example there are more properties for each object. If Json contains type = "Boy" how can I generate the boy object.
Example JSON:
string json = #"
{
'name': 'Object 1',
'content': {
'body': {
'id': 'body',
'type': 'Body'
},
'style': {
'id': 'style',
'type': 'Style'
},
'DynamicName-123': {
'id': 'DynamicName-123',
'type': 'Row'
'model': {},
'colors': []
},
'DynamicName-434': {
'id': 'DynamicName-434',
'type': 'Column'
'model': {},
'colors': []
},
'DynamicName-223': {
'id': 'DynamicName-223',
'type': 'Item'
'model': {},
'colors': []
}
}
}";

If your key/value pair are not fixed and data must be configurable then Newtonsoft.json has one feature that to be use here and that is [JsonExtensionData] Read more
Extension data is now written when an object is serialized. Reading and writing extension data makes it possible to automatically round-trip all JSON without adding every property to the .NET type you’re deserializing to. Only declare the properties you’re interested in and let extension data do the rest.
In your case, suppose there is a class,
public class MyClass
{
public string Qaz { get; set; }
public string Wsx { get; set; }
[JsonExtensionData]
public Dictionary<string, JToken> child { get; set; }
public MyClass()
{
child = new Dictionary<string, JToken>();
}
}
In the above class, you know that Qaz and Wsx are always present from your json either they contain value or null,
But for dynamic data, you can't say which key/value pair you will receive from your json so the [JsonExtensionData] can collect all those key/value pair in a dictionary.
Suppose the below classes will be for your dynamic data,
public class ABC
{
public string Abc { get; set; }
}
public class PQR
{
public string Pqr { get; set; }
}
public class XYZ
{
public string Xyz { get; set; }
}
Serialization:
ABC aBC = new ABC { Abc = "abc" };
PQR pQR = new PQR { Pqr = "pqr" };
XYZ xYZ = new XYZ { Xyz = "xyz" };
MyClass myClass = new MyClass();
myClass.Qaz = "qaz";
myClass.Wsx = "wsx";
myClass.child.Add("ABC", JToken.FromObject(aBC));
myClass.child.Add("PQR", JToken.FromObject(pQR));
myClass.child.Add("XYZ", JToken.FromObject(xYZ));
string outputJson = JsonConvert.SerializeObject(myClass);
This will give you json like
{
"Qaz": "qaz",
"Wsx": "wsx",
"ABC": {
"Abc": "abc"
},
"PQR": {
"Pqr": "pqr"
},
"XYZ": {
"Xyz": "xyz"
}
}
Deserialization:
MyClass myClass = JsonConvert.DeserializeObject<MyClass>(outputJson);
string Qaz = myClass.Qaz;
string Wsx = myClass.Wsx;
if (myClass.child.ContainsKey("ABC"))
{
ABC abcObj = myClass.child["ABC"].ToObject<ABC>();
}
if (myClass.child.ContainsKey("PQR"))
{
PQR pqrObj = myClass.child["PQR"].ToObject<PQR>();
}
if (myClass.child.ContainsKey("XYZ"))
{
XYZ pqrObj = myClass.child["XYZ"].ToObject<XYZ>();
}
Conclusion: The main aim of [JsonExtensionData] is to keep your json class hierarchy simple and more readable so you don't need to manage class structure for every property.
Get all dynamic data with the specific key in JToken inside Dictionary :
You can use LINQ to fetch all dynamic data of particular key from the above dictionary.
var allAbcTypes = myClass.child
.SelectMany(x => x.Value
.ToObject<JObject>()
.Properties()
.Where(p => p.Name == "Abc") //<= Use "Column" instead of "Abc"
.Select(o => new ABC //<= Use your type that contais "Column" as a property
{
Abc = o.Value.ToString()
})).ToList();
In your case, Its something like,
var allColumnTypes = myClass.child
.SelectMany(x => x.Value
.ToObject<JObject>()
.Properties()
.Where(p => p.Name == "Column")
.Select(o => new Item
{
id = x.Value["id "].ToString(),
type = x.Value["type "].ToString(),
model = x.Value["model"].ToObject<List<string>>(),
color = x.Value["color"].ToObject<string[]>()
})).ToList();

If you want to deserialize to a dictionary with a Key string and a dynamic value (boy or girl in this case), the only way I Know is using Dynamic class:
public List<Dictionary<string, dynamic>> child { get; set; }

Related

How to deserialize a JObject that brings the data as Item1 , Item2?

I have ([FromBody] JObject jObject) to my method.
The jObject brings the data like:
{{
"Item1": {
"AssocEmployee": { ... },
"ID": 79
},
"Item2": null
}}
Inside the method i am trying something like this :
var empAssignment = new EmployeeAssignment();
//var empAssignment = jObject.ToObject<EmployeeAssignment>();
//empAssignment.ID = jObject.Value<JArray>("Item1").Values<int>("id").FirstOrDefault();
empAssignment.ID = jObject["id"].Value<int>();
empAssignment.AssocEmployee = jObject.ToObject<Employee>();
The Item2 that is null is not a problem.
Item1 and Item2 are coming from Tuple. The real names of classes are EmployeeAssignment and Position.
You have to fix your json, by removing an extra pair of {}, after this try this code
var items =JsonConvert.DeserializeObject<Items>(json);
var empAssignment =items.EmployeeAssignment;
var assocEmployee= empAssignment.AssocEmployee;
var empAssignmentId = empAssignment.ID;
classes
public class Items
{
[JsonProperty("Item1")]
public EmployeeAssignment EmployeeAssignment { get; set; }
[JsonProperty("Item2")]
public object Item2 { get; set; }
}
public class EmployeeAssignment
{
[JsonProperty("AssocEmployee")]
public AssocEmployee AssocEmployee { get; set; }
[JsonProperty("ID")]
public int ID { get; set; }
}
public class AssocEmployee
{
}

Convert json string from one type to another with .net core c#

I am struggling to convert below input json to output json as this is what is the required format to call
hubspot api to submit a form. I am writing this using .net core within Azure function.
Input Json
{
"Email":"myemail#test.com",
"Phone":"12345678",
"Address":"address 1"
}
Output json
{
"fields": [
{
"name": "Email",
"value": "myemail#test.com"
},
{
"name": "Phone",
"value": "12345678"
},
{
"name": "Address",
"value": "address 1"
}
]
}
I converted the input json to dictionary using
IDictionary<string, string> dictionary = JsonConvert.DeserializeObject<IDictionary<string, string>>(inputJson);
but that gives me key value pair instead of name value pair.
I would like the output as detailed above.
Any help/example code would be highly appreciated.
You could create your own "NameValuePair" class/struct if you don't want "Key" as the field name:
public class FieldContainer
{
[JsonProperty("fields")]
public IEnumerable<NameValuePair> Fields { get; set; }
}
public struct NameValuePair
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("value")]
public string Value { get; set; }
public NameValuePair(string name, string value)
{
Name = name;
Value = value;
}
}
And then do like you've already done, but converting the KeyValuePairs into your own struct:
var inJson = #"{
""Email"":""myemail#test.com"",
""Phone"":""12345678"",
""Address"":""address 1""
}";
var dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(inJson);
var container = new FieldContainer
{
Fields = dict.Select(pair => new NameValuePair(pair.Key, pair.Value))
};
var outJson = JsonConvert.SerializeObject(container);
See this fiddle for a demonstration.
Easiest way to do this would be to take the json and convert it to Dictionary<string, string>. Loop over each KeyValuePair and create a list of Fields using LINQ. Once you have the List of fields, create your RootObject.
public class RootObject
{
[JsonProperty("fields")]
public List<Field> Fields { get; set; }
}
public class Field
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("value")]
public string Value { get; set; }
}
// Create a dictionary
var dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonStr);
// Create a list of Fields
List<Field> fields = dict.Select(x => new Field() { Name = x.Key, Value = x.Value }).ToList();
// Create the final Object.
RootObject rootObj = JsonConvert.SerializeObject(new RootObject() { Fields = fields });
Alternative solution, using JObject.Parse() to parse the original JSON, then iterate its Properties to create an array of JObjects with different names and values.
The resulting IEnumerable<JObject> is then converted to a JArray, used to create the final fields object.
var jObj = JObject.Parse(json);
var newObjects = jObj.Properties().Select(p => new JObject {
new JProperty("name", p.Name),
new JProperty("value", p.Value)});
var fields = new JObject() {
{ "fields", JArray.FromObject(newObjects)}
};
Console.WriteLine(fields);

Json parse sub-collection in c#

How can I do JSON in C# like the data below ?
{
"Aliases": [ "teddy", "freddy", "eddy", "Betty" ],
"Name":"reacher gilt",
"Address":"100 East Way",
"Age":74,
"Bars": {
"items": [
{
"Sub_Property1":"beep",
"Sub_Property2":"boop"
},
{
"Sub_Property1":"meep",
"Sub_Property2":"moop"
},
{
"Sub_Property1":"feep",
"Sub_Property2":"foop"
}
]
}
}
Actually my problem is inside the sub-collection. I saw someone did something
like this
person.Bars.Add("items",
new List<BarClass>(new[]{
new BarClass("beep","boop"),
new BarClass("meep","moop"),
new BarClass("feep","foop"),
}));
So, I have to add new BarClass("beep","boop"), but I need to do something
like this
String [] no1 = {1,2,3}
String [] no2 = {4,5,6}
person.Bars.Add("items",
new List<BarClass>(new[]{
for ()
{
new BarClass(no1[i],no2[i])
}
}));
How can i do this? Thanks and please help..
To read the JSON
The best way to read the whole JSON is to Deserialize it to a native C# object. If you do not already have the classes with your, you can create it in Visual Studio as
Copy your JSON text
Create a new empty class file in VS
Edit > Paste Special > Paste JSON As Classes
Here are the classes
public class Person
{
public string[] Aliases { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public Bars Bars { get; set; }
}
public class Bars
{
public Item[] items { get; set; }
}
public class Item
{
public string Sub_Property1 { get; set; }
public string Sub_Property2 { get; set; }
}
Now you can use some .NET JSON library to deserialize. JSON.Net aka Newtonsoft JSON is a great library. You get get it from NuGet as well.
Then it's pretty easy to get the C# object from the JSON
//using Newtonsoft.Json;
var jsonString = File.ReadAllText(#"C:\YourDirectory\person.json");
var person = JsonConvert.DeserializeObject<Person>(jsonString);
If you want to read the sub-collection only, you can rather use Linq-to-JSON to read the items directly, like this
//using Newtonsoft.Json.Linq;
var jObject = JObject.Parse(jsonString);
List<Item> details = jObject["Bars"]["items"].ToObject<List<Item>>();
To create the JSON
You first need to create the object, then Serialize to JSON
string[] subProperties1 = new string[] { "1", "2", "3" };
string[] subProperties2 = new string[] { "4", "5", "6" };
Person person = new Person { Name = "Johny", Age = 7, Address = "Earth", Aliases = new string[] { "Sony", "Monty" } };
person.Bars = new Bars {
items = subProperties1.Zip(subProperties2,
(prop1, prop2) => new Item { Sub_Property1 = prop1, Sub_Property2 = prop2 })
.ToArray() };
var json = JsonConvert.SerializeObject(person);
To create the items from your existing string arrays, I have used IEnumerable.Zip function from Linq. You can read about them here.
This is the created JSON data
{
"Aliases": [ "Sony", "Monty" ],
"Name": "Johny",
"Address": "Earth",
"Age": 7,
"Bars": {
"items": [
{
"Sub_Property1": "1",
"Sub_Property2": "4"
},
{
"Sub_Property1": "2",
"Sub_Property2": "5"
},
{
"Sub_Property1": "3",
"Sub_Property2": "6"
}
]
}
}
You should create some classes
public class Person
{
public string Name {get;set;}
public string Address{get;set;}
public int Age {get;set;}
public Header {get;set;}
}
public class Header
{
public Detail[] Details {get;set;}
}
public class Detail
{
public string Sub1 {get;set;}
public string Sub2 {get;set;}
}
Create instance from Person class and initialize to instance after than
JavaScriptSerializer serializer =new JavaScriptSerializer();
var result=serializer.Serialize(instanceOfPerson);
"result" is json data
Assuming that you mean you want to create JSON string, you need to create those classes and use something like Newtonsoft JSON.net:
public class Item
{
public string Sub_Property1 { get; set; }
public string Sub_Property2 { get; set; }
}
public class Bars
{
public List<Item> items { get; set; }
}
public class Person
{
public List<string> Aliases { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public Bars Bars { get; set; }
}
Please read the documentation here: http://www.newtonsoft.com/json/help/html/Introduction.htm

Deserialize Nested JSON to Lists

I am trying to bind a drop-down with these lists in my View. Not able to convert the below JSON collections to LISTS.
My JSON string is in this format:
["AppTypes",
[
{
"AppTypeID": "5136",
"AppType": "ABC"
},
{
"AppTypeID": "dca6",
"AppType": "MNO"
},
{
"AppTypeID": "d8de",
"AppType": "PQR"
}
],
"CompTypes",
[
{
"CompTypeID": "0425",
"CompType": "STU"
},
{
"CompTypeID": "0426",
"CompType": "EDC"
},
{
"CompTypeID": "0444",
"CompType": "PLM"
}
]
]
I am trying to deserialize the code, but not getting through. My Class,
public class DAL
{
public DAL() { }
public CompList CompList { get; set; }
}
public class CompList
{
public CompList()
{
AppTypes = new List<AppTypes>();
CompType = new List<CompTypes>();
}
public List<AppTypes> AppTypes;
public List<ComTypes> CompType;
}
public class AppTypes
{
public Guid AppTypeID { get; set; }
public string AppType { get; set; }
}
public class CompTypes
{
public Guid CompTypeID { get; set; }
public string CompType { get; set; }
}
public class JSONSerializer
{
public static T ConvertFromJSON<T>(String json)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Deserialize<T>(json);
}
}
Controller Code:
dynamic obj = JSONSerializer.ConvertFromJSON<DAL>(JsonData);
Not able to get where I am going wrong. Any help would be really appreciated.
The main problem here is that your JSON represents a top-level array containing either strings or nested arrays containing objects, but you are trying to deserialize this into a top-level object - not an array. Your class design is quite reasonable, but a serializer such as JavaScriptSerializer isn't really designed to completely restructure a data model in this way during deserialization. You may need to deserialize into a more literal representation of the JSON, then restructure the data with, say, Linq.
A secondary problem is that you are declaring your ID properties to be Guids, but the corresponding JSON properties (such as "AppTypeID": "5136") do not have enough digits to be Guids. JavaScriptSerializer expects a Guid to have 32 digits, optionally separated by hyphens, e.g.: "d70d7583-b2e6-4f6e-8d99-2022d3ca2b10" or "d70d7583b2e64f6e8d992022d3ca2b10".
Thus, if I change your Guid properties to strings:
public class AppTypes
{
public string AppTypeID { get; set; }
public string AppType { get; set; }
}
public class CompTypes
{
public string CompTypeID { get; set; }
public string CompType { get; set; }
}
Then I can deserialize and convert to a CompList as follows:
var js = new JavaScriptSerializer();
var array = js.Deserialize<List<object>>(JsonData); // Deserialize outer array
var compList = new CompList
{
AppTypes = array
.OfType<IEnumerable<object>>() // Enumerate through nested arrays
.SelectMany(o => o) // Enumerate through elements in nested arrays
.OfType<IDictionary<string, object>>() // Pick out those which are JSON objects (deserialized as dictionaries)
.Where(d => d.ContainsKey("AppType")) // Filter those that are AppTypes
.Select(d => js.ConvertToType<AppTypes>(d)) // Deserialize to the AppTypes class
.ToList(),
CompType = array
.OfType<IEnumerable<object>>()
.SelectMany(o => o)
.OfType<IDictionary<string, object>>()
.Where(d => d.ContainsKey("CompType"))
.Select(d => js.ConvertToType<CompTypes>(d))
.ToList(),
};
FYI, your original code could deserialize JSON that looks like this into a CompList:
{
"AppTypes": [
{
"AppTypeID": "5136",
"AppType": "ABC"
},
{
"AppTypeID": "dca6",
"AppType": "MNO"
},
{
"AppTypeID": "d8de",
"AppType": "PQR"
}
],
"CompType": [
{
"CompTypeID": "0425",
"CompType": "STU"
},
{
"CompTypeID": "0426",
"CompType": "EDC"
},
{
"CompTypeID": "0444",
"CompType": "PLM"
}
]
}
Note that the outermost JSON is an object with two array-valued properties rather than an array of two strings and two arrays.

c# JavaScriptSerializer on JSON containing string + dictionary

May i know how to parsing the JSON stated as below..... the JSON is part of Yahoo OAuth Contacts list.
JSON:
"fields":[{
"id":2,
"type":"nickname",
"value":"Hello"
},
{
"id":3,
"type":"email",
"value":"MyTesting#hotmail.com"
},
{
"id":1,
"type":"name",
"value":{
"givenName":"Otopass",
"middleName":"Test",
"familyName":"Hotmail"
},
}],
C# object :
private class fields
{
public string id { get; set; }
public string type { get; set; }
//public string value { get; set; } //Stuck At Here !!!!
//public Dictionary<string, string> value { get; set; } //Stuck At Here !!!!
}
How to parse the "value"?? since it's combination type of String & Dictionary.
I can't answer it using JavaScriptSerializer but you can do it using json.Net and Linq
var jObj = JObject.Parse(json);
var fields = jObj["fields"]
.Select(x => new Field
{
Id = (int)x["id"],
Type = (string)x["type"],
Value = x["value"] is JValue
? new Dictionary<string,string>(){{"",(string)x["value"]}}
: x["value"].Children()
.Cast<JProperty>()
.ToDictionary(p => p.Name, p => (string)p.Value)
})
.ToList();
private class Field
{
public int Id { get; set; }
public string Type { get; set; }
public Dictionary<string, string> Value { get; set; }
}
PS: I fixed your partial json string as
string json =
#"{""fields"":[
{
""id"":2,
""type"":""nickname"",
""value"":""Hello""
},
{
""id"":3,
""type"":""email"",
""value"":""MyTesting#hotmail.com""
},
{
""id"":1,
""type"":""name"",
""value"":{
""givenName"":""Otopass"",
""middleName"":""Test"",
""familyName"":""Hotmail""
}
}
]}";

Categories

Resources