Newtonsoft Json Serializer/Deserializer - how to use generic objects instead of JObject? - c#

I have JSON specified by a restful service I am consuming that looks like this as an example:
{
"id": "97",
"name": "Tom Production",
"description": null,
"parameters": [
{
"first_parameter_name": "First Parameter Value"
},
{
"second_parameter_name": "Second Parameter Value"
}
]
}
Note that the property names id, name, description, and parameters are all established as part of the specification. The collection of generic parameters, shown in my example as "first_parameter_name" and "second_parameter_name" are not specified.... could be anything and I want to map them to generically typed objects.
I have declared an object for this as:
[DataContract (Name = "MyClass")]
public class MyClass
{
[DataMember (Name = "id")]
public string Id { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "description")]
public string Description { get; set; }
[DataMember(Name = "parameters")]
public List<object> Parameters { get; set; }
}
Serialization works fine, exactly as I expect:
var myObject = new MyClass();
myObject.Id = "97";
myObject.Name = "Tom Production";
myObject.Parameters = new List<object>();
myObject.Parameters.Add(new { first_parameter_name = "First Parameter Value" });
myObject.Parameters.Add(new { second_parameter_name = "Second Parameter Value" });
string json = JsonConvert.SerializeObject(myObject);
Console.WriteLine(json);
yields the JSON I am looking for, exactly as at the top of this posting.
HOWEVER.
Deserialization does NOT work fine. If it worked the way I hope it to, which would be to create generic types just like I had created, and the following code should work.... but instead it throws a reflection exception:
var myNewObject = JsonConvert.DeserializeObject<MyClass>(json);
foreach (object o in myNewObject.Parameters)
{
Type t = o.GetType();
Console.WriteLine("\tType is {0}", t);
foreach (PropertyInfo pi in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
Console.WriteLine("\t\tName is {0}", pi.Name);
Console.WriteLine("\t\tValue is {0}", pi.GetValue(o, null));
}
}
Instead, I have to write code that is Newtonsoft-specific (ick) to use a kind of fake Newtonsoft reflection:
var myNewObject = JsonConvert.DeserializeObject<MyClass>(json);
foreach (object o in myNewObject.Parameters)
{
var jo = o as JObject;
if (jo != null)
{
foreach (JProperty prop in jo.Properties())
{
Console.WriteLine("\t\tName is {0}", prop.Name);
Console.WriteLine("\t\tValue is {0}", prop.Value);
}
}
}
Is there a way that I can control the Deserializer so that it will generate the proper generic types rather than the JObject type with the JProperties?
Many thanks in advance.

JObjects map most directly to Dictionary<string, object>s, since they're each simply a collection of keys to values. If you know that the value is always a string, you can make it a Dictionary<string, string>.
[DataMember(Name = "parameters")]
public List<Dictionary<string, object>> Parameters { get; set; }
// or
[DataMember(Name = "parameters")]
public List<Dictionary<string, string>> Parameters { get; set; }
// e.g.
var myNewObject = JsonConvert.DeserializeObject<MyClass>(json);
foreach (var dict in myNewObject.Parameters)
{
foreach (var pair in dict)
{
Console.WriteLine("\t\tKey is {0}", pair.Key);
Console.WriteLine("\t\tValue is {0}", pair.Value);
}
}

Related

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 to C# object handling dynamic properties

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; }

How to get element in JSON string

I have this JSON string called assignee:
{
"id": 15247055788906,
"gid": "15247055788906",
"name": "Bo Sundahl",
"resource_type": "user"
}
I want to get the "name" element and its value if it's not null. I have tried
var jobject = JsonConvert.DeserializeObject<JObject>(assignee);
And
var jo = JObject.Parse(assignee);
I tried looping through it but I just get null exception or empty output even though if I just print the assignee variable itself its filled with data.
My loop is like:
foreach (var result in jobject["name"])
{
Debug.WriteLine(result);
}
The simplest and best way is to deserialise to a C# class, for example:
public class Data
{
public long Id { get; set; }
public string Name { get; set; }
//etc..
}
And deserialise like this
var data = JsonConvert.DeserializeObject<Data>(json);
var name = data.Name;
To get name use this
string name = jobject["name"];
Using ["name"] returns a JToken, it is null if the property doesn't exist
JToken token = jo["name"];
Debug.WriteLine(token?.ToString() ?? "<default value>");
If you don't know properties beforehand, you can loop through JObject properties and get name value pairs as following:
var jsonObject = JObject.Parse(str);
foreach (var item in jsonObject)
{
var name = item.Key;
JToken token = item.Value;
if (token is JValue)
{
var value = token.Value<string>();
}
}
Here is how it should work:
class Data
{
public long? Id { get; set; }
public string Gid { get; set; }
public string Name { get; set; }
public string Resource_Type { get; set; }
}
class Program
{
static void Main(string[] args)
{
string assignee = "{\"id\": 15247055788906, \"gid\": \"15247055788906\", \"name\": \"Bo Sundahl\", \"resource_type\": \"user\"}";
Data data = JsonConvert.DeserializeObject<Data>(assignee);
Console.WriteLine(data.Id);
Console.WriteLine(data.Gid);
Console.WriteLine(data.Name);
Console.WriteLine(data.Resource_Type);
Console.ReadLine();
}
}

Print object with nested properties as string of comma separated key-value pairs

I have a Person class:
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string Line1 { get; set; }
public string Line2 { get; set; }
}
As an end result, I would like to print out a Person instance as JSON, but I'd like it to be a huge string of key-value pairs, e.g.:
"Name:John,Surname:Doe,Line1:Infinite Loop,Line2:California"
Notice that in the example above, I got rid of the actual class names (i.e. it prints out Line1 instead of Address.Line1) - i only care about all the name/value pairs.
So the end result would be an array of Persons:
"persons":[
"Name:John,Surname:Doe,Line1:Infinite Loop 1,Line2:California",
"Name:Jane,Surname:Doe,Line1:Infinite Loop 2,Line2:California"
]
As a starting point, I tried using reflection:
void Main()
{
var persons = new List<Person>();
persons.Add(new Person
{
Name = "John",
Surname = "Doe",
Address = new Address
{
Line1 = "Infinite Loop",
Line2 = "California"
}
});
foreach(var person in persons)
{
var properties = new List<string>();
foreach(var property in person.GetType().GetProperties())
{
properties.Add($"{property.Name}:{property.GetValue(person, null)}");
}
Console.WriteLine(string.Join(",", properties));
}
}
But I get the following output in LINQPad:
Name:John,Surname:Doe,Address:UserQuery+Address
I assume Address is not properly iterated upon because it's a nested object within Person. Even so, this doesn't look like the most clean/efficient approach.
You could do this using a custom JsonConverter like so:
class PersonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Person);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var pairs = JObject.FromObject(value)
.Descendants()
.OfType<JProperty>()
.Where(p => p.Value is JValue)
.Select(p => p.Name + ":" + p.Value);
writer.WriteValue(string.Join(",", pairs));
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Then use it by passing the converter to JsonConvert.SerializeObject like this:
string json = JsonConvert.SerializeObject(obj, Formatting.Indented, new PersonConverter());
Here is a working demo: https://dotnetfiddle.net/L4YDsm
Add a ToString override to your class and return a collection of strings as JSON.
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public Address Address { get; set; }
public override string ToString()
{
return $"Name:{Name},Surname:{Surname},Line1:{Address?.Line1},Line2:{Address?.Line2}";
}
}
You must implement the reflection in a way that it could go deeper into the structure of your object in order to do what you want. Here's a simple recursive and generic adaptation to your provided code.
public static string GetRecursivePropertyValues(object obj)
{
var properties = new List<string>();
foreach (var property in obj.GetType().GetProperties())
{
object currentPropertyValue = property.GetValue(obj);
if (property.PropertyType.IsPrimitive || property.PropertyType == typeof(string))
properties.Add($"{property.Name}:{currentPropertyValue}");
else
{
var subProperties = GetRecursivePropertyValues(currentPropertyValue);
properties.Add(subProperties);
}
}
return string.Join(";", properties);
}
This implementation first verifies if each property is defined with a primitive type or string (which are not considered primitive types in C#) and prints them normally if that's the case. Else, if the type is complex (like if it is declared as an Address instance), it recursivelly retrieves the properties of the complex object, and adds them to the resulting string.
You can call it like:
string propertiesStr = GetRecursivePropertyValues(person);
Edit: code now only flattens the object as required by OP (previous code sample used some rustic JSON formatting).
Using Newtonsoft.json
https://www.newtonsoft.com/json/help/html/SerializingJSON.htm
Check the above link... It will tell you how to serialize an object to json, it's important to note, you will want to add all your items to a list, then serialize the list into json to get the desired effect
Product product = new Product();
product.Name = "Apple";
product.ExpiryDate = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
There example:
string output = JsonConvert.SerializeObject(product);
//{
// "Name": "Apple",
// "ExpiryDate": "2008-12-28T00:00:00",
// "Price": 3.99,
// "Sizes": [
// "Small",
// "Medium",
// "Large"
// ]
//}

map entity to runtime created dto

Is there an automagic (automapper?) way to map an entity to a runtime created dynamic object with properties passed as parameters? I want to do an API where the clients can select the properties of the entities they want to fetch.
I mean:
class Patient
{
public int PatientId{ get; set; }
public string Name{ get; set; }
public string LastName{ get; set; }
public string Address{ get; set; }
...
}
getPatient(string[] properties)
{
//Return an object that has the properties passed as parameters
}
Imagine you only want to fetch a PatientDTO with PatientId and Name:
getPatient(new string[]{"PatientId", "Name"}
should return
{
"PatientId": "1234",
"Name": "Martin",
}
and so on.
For now I'm doing it with Dictionary, but probably there is a better way. This is my approach:
For a single object:
public static Dictionary<string, object> getDTO(string[] properties, T entity)
{
var dto = new Dictionary<string, object>();
foreach (string s in properties)
{
dto.Add(s, typeof(T).GetProperty(s).GetValue(entity));
}
return dto;
}
For a list of objects:
public static List<Dictionary<string, object>> getDTOList(string[] properties, List<T> TList)
{
var dtoList = new List<Dictionary<string, object>>();
foreach(T entity in TList)
{
dtoList.Add(getDTO(properties, entity));
}
return dtoList;
}
Thank you.
How about creating a new dynamic object based solely on the specified property fields and returning the dynamic?
You will need to add using statements for: System.Dynamic and System.ComponentModel for the following to work.
public static dynamic getDTO(object entity, string[] properties)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (var p in properties)
{
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(entity.GetType()))
{
if (property.Name == p)
{
expando.Add(p, property.GetValue(entity));
break;
}
}
}
return expando as ExpandoObject;
}
Calling this method would look something like this:
var patient = new Patient() { PatientId = 1, Name = "Joe", LastName = "Smith", Address = "123 Some Street\nIn Some Town, FL 32333" };
var propList = new string[] { "PatientId", "Name", "Address" };
dynamic result = getDTO(patient, propList);
Console.WriteLine("Id:{0} Name: {1}\nAddress: {2}", result.PatientId, result.Name, result.Address);
Console.ReadLine();

Categories

Resources