C# Custom Json.NET List serialization - c#

I have a List of DataObject classes:
public class DataObject
{
public string Name { get; set; }
public List<Field> Fields { get; set; }
}
}
public class Field
{
public string Name { get; set;}
public string Type { get; set; }
public Object Value { get; set; }
public Field(string name, string type, string value)
{
Name = name;
Type = type;
if(type == "string") Value = (string)value;
else Value = Int32.Parse(value);
}
}
and i would like to serialize List made of DataObject classes to .json file. the way I show below using Json.NET, I have tried few scenarios but didn't find out how to do this.
Example:
Field field1 = new Field("Brand", "string", "Volvo);
Field field2 = new Field("Power", "int", 200);
List<Field> fields = new List<Field>{field1, field2};
DataObject car = new DataObject{
Name = "Car",
Fields = list
}
List<DataObjects> objects = new List<DataObjects>{car};
Result:
{
"Car":{
"Brand" : "Volvo",
"Power" : 200
}
}

Using Newtonsoft.Json, Serialization is rather easy. I took your code and added the following line:
string json = JsonConvert.SerializeObject(objects, Newtonsoft.Json.Formatting.Indented);
and it gave me the following output:
[
{
"Name": "Car",
"Fields": [
{
"Name": "Brand",
"Type": "string",
"Value": "Volvo"
},
{
"Name": "Power",
"Type": "int",
"Value": 200
}
]
}
]

Related

How do I create a List or Array of different data types from C# to be saved to JSON in Unity

I would like my output JSON to contain a simple array shown below
{
"attributes":[
{
"trait_type": "Background",
"value": "Green"
},
{
"trait_type": "Body",
"value": "Body_1"
},
{
"trait_type": "Outfit",
"value": "Beach_Singlet"
},
{
"display_type":"date",
"trait_type":"birthday",
"value":869270400
}
]
}
Notice how the last item is different from the previous items in the array. The variable named "value" is also an integer as compared to the previous entries as strings.
How do I go about in order to be able to output my JSON as shown above? I have tried creating a class that can store all the information, but I cannot reuse the name "value" for both an int and string declaration, and also do not wish to show the variables if their value is null
(Example shown below)
{
"attributes": [
{
"display_type": "",
"trait_type": "Background",
"value": "Green"
},
{
"display_type": "",
"trait_type": "Body",
"value": "Body_1"
},
{
"display_type": "",
"trait_type": "Outfit",
"value": "Beach_Singlet"
},
{
"display_type": "date",
"trait_type": "birthday",
"value": 869270400
}
]
}
You can use object type.
using Newtonsoft.Json;
var list = new AttributeList
{
attributes = new []{
new Attribute
{
trait_type = "Background",
value = "green"
},
new Attribute
{
display_type = "date",
trait_type = "birthday",
value = 869270400
}
}
};
var json = JsonConvert.SerializeObject(list, Formatting.Indented);
Console.WriteLine(json);
public class Attribute
{
public object value { get; set; }
public string trait_type { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string display_type { get; set; }
}
public class AttributeList
{
public Attribute[] attributes { get; set; }
}
Output:
{
"attributes": [
{
"value": "green",
"trait_type": "Background"
},
{
"value": 869270400,
"trait_type": "birthday",
"display_type": "date"
}
]
}
try this
var attributes=new List<Attribute>{
new AttributeString{
trait_type="Background",
value="green"
},
new AttributeInt{
display_type ="date",
trait_type="birthday",
value=869270400
}
};
var jsonSerializerSettings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects,
NullValueHandling=NullValueHandling.Ignore,
Formatting=Newtonsoft.Json.Formatting.Indented
};
var json = JsonConvert.SerializeObject(attributes,jsonSerializerSettings);
classes
public class Attribute
{
public string trait_type { get; set; }
public string display_type { get; set; }
}
public class AttributeString:Attribute
{
public string value { get; set; }
}
public class AttributeInt:Attribute
{
public int value { get; set; }
}
public class AttributeList
{
public List<Attribute> attributes { get; set; }
}

JsonConvert DeserializeObject with objects with inheritance

I have for example these classes
public class JsonResult
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("myobjects")]
public List<BaseClass> myObjects { get; set; }
}
public abstract class BaseClass
{
[JsonProperty("name")]
public string Name { get; set; }
}
public class FlavourOne: BaseClass
{
[JsonProperty("number")]
public int Number { get; set; }
[JsonProperty("mytext")]
public string MyText { get; set; }
}
public class FlavourTwo: BaseClass
{
[JsonProperty("yourtext")]
public string YourText { get; set; }
}
And i have this Json object coming in as a string
{
"name": "examplename",
"myobjects": [
{
"name": "myFlavourOneInstance",
"number": 1,
"mytext": "Text from One"
},
{
"name": "myFlavourTwoInstance",
"yourtext": "Your Text from Two"
}
]
}
I would like to have an object from that Json string as follows
var responseObject = JsonConvert.DeserializeObject<JsonResult>(rawJsonString);
But this does not work, is there a nice and clean way to have the json into the object with inherited classes and so on?
Yes, you can specify the class in the Json for deserialization using TypeNameHandling.Auto (or TypeNameHandling.All, depending on your use case).
Here's an example using TypeNameHandling.Auto:
void Main() {
var jsonResult = new JsonResult {
Name = "test",
myObjects = new List<BaseClass> {
new FlavourOne {
Name = nameof(FlavourOne),
Number = 1,
MyText = "Text from one"
},
new FlavourTwo {
Name = nameof(FlavourTwo),
YourText = "Text from two"
}
}
};
var serializerSettings = new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.Auto
};
var json = JsonConvert.SerializeObject(jsonResult, Formatting.Indented, serializerSettings);
Console.WriteLine(json);
}
// Your classes here
Output:
{
"name": "test",
"myobjects": [
{
"$type": "FlavourOne, AssemblyName",
"number": 1,
"mytext": "Text from one",
"name": "FlavourOne"
},
{
"$type": "FlavourTwo, AssemblyName",
"yourtext": "Text from two",
"name": "FlavourTwo"
}
]
}
This means that when deserialized, they are assigned the correct type, as long as you use the same serializer settings:
var responseObject = JsonConvert.DeserializeObject<JsonResult>(json, serializerSettings);
Note though, as per the docs:
TypeNameHandling should be used with caution when your application deserializes JSON from an external source.
This is because you don't want to let external Json create arbitrary types!

Convert custome Key+Value JSON object Response to C# Model

i have this API that i want to creat a dynamic object. My point here is to have normal object to deal with rather than what this API returns to me, i can't controll this API so the retrived data can't be modified, this is the body, and it represnet a view in Database
Also i think reflection could help me in this case, any idea....
Request Body:
{
"ViewName": "Person",
"ViewOutput": "Name, Email, Number",
"ViewFilter": [
{
"filterKey": "Number",
"filterValue": "532000000"
}
]
}
I want the ViewName + ViewOutput+ ViewFilter to be paramterized,
ViewName it will take single value,
ViewOutput will be array of string
ViewFilter will be list of filteration ("FilterKey", "FilterVlaue") because it could be mutliple filteration value like this:
"ViewFilter": [
{
"filterKey": "Number",
"filterValue": "532000000"
},
{
"filterKey": "Email",
"filterValue": "test1#test.ps"
}
]
This is What API Return to me, a list of Person Keys and values,
Response:
{
"ResponseCode": "0",
"ResponseMessage": "Success",
"NumberOfRecords": "1",
"MainData": [
{
"recordData": [
{
"dataKey": "Name",
"dataValue": "Test Name"
},
{
"dataKey": "Email",
"dataValue": "test#test.ps"
},
{
"dataKey": "Number",
"dataValue": "532000000"
}
]
}
]
}
What i want to be the output is like this:
"Person": [
{
"Name":"Test",
"Email":"test#test.ps",
"Number":"532000000",
}]
Pasting the response JSON into an empty class file in Visual Studio using the Paste JSON As Classes feature, yields these classes:
public class Rootobject
{
public string ResponseCode { get; set; }
public string ResponseMessage { get; set; }
public string NumberOfRecords { get; set; }
public Maindata[] MainData { get; set; }
}
public class Maindata
{
public Recorddata[] recordData { get; set; }
}
public class Recorddata
{
public string dataKey { get; set; }
public string dataValue { get; set; }
}
You can create your own Person class.
Once you deserialize the JSON into the generated classes, one way to get a List<Person> would be to do something like this (please note that this is untested example code):
var people = rootObject.Maindata.Select(r =>
{
var name = r.recordData.Single(d => d.dataKey == "Name").dataValue;
var email = r.recordData.Single(d => d.dataKey == "Email").dataValue;
var number = r.recordData.Single(d => d.dataKey == "Number").dataValue;
return new Person(name, email, number);
}).ToList();

Convert IEnumerable<object> results to List<Account>

I have a salesforce rest service which returns results in IEnumerable format. Below is a sample results.
[{
"attributes": {
"type": "Account",
"url": "/services/data/v28.0/sobjects/Account/001i0000WK5xYAAT"
},
"RecordType": {
"attributes": {
"type": "RecordType",
"url": "/services/data/v28.0/sobjects/RecordType/012i00000x7FwAAI"
},
"Name": "Health Care Practitioners"
},
"Name": "JOSEPH SANDERS",
"Status_ims__c": "Verified",
},
{
"attributes": {
"type": "Account",
"url": "/services/data/v28.0/sobjects/Account/001i000000WK5xYAAT"
},
"RecordType": {
"attributes": {
"type": "RecordType",
"url": "/services/data/v28.0/sobjects/RecordType/012i0000000x7FwAAI"
},
"Name": "Health Care Practitioners"
},
"Name": "DONALD GRABER",
"Status_ims__c": "Verified",
}]
public class Account
{
public string Name { get{ return GetOption ("Name");} }
public string Status_ims__c { get{ return GetOption ("Status_ims__c");}}
public Attributes attributes {get;}
public RecordType recordType {get;}
}
public class Attributes
{
public string type { get; set; }
public string url { get; set; }
}
public class Attributes2
{
public string type { get; set; }
public string url { get; set; }
}
public class RecordType
{
public Attributes2 attributes { get; set; }
public string Name { get; set; }
}
Above is the structure I have for Account Object. How to convert results to List and map to each property on Account object.
For Example is using json.net ->
var account = JsonConvert.DeserializeObject<List<Account>>(stringData);
Also if there are some differences between the object and the data you can use JsonProperty Annotations
Therefore you could also have more readable properties in your class model like
[JsonProperty("Status_ims__c ")]
public string Status
You can simple use this:
var accounts = JsonConvert.DeserializeObject<List<Account>>("your json string...");
If you use Newtonsoft.Json you can use Newtonsoft.Json.JsonConvert.DeserializeObject method.
Also make sure that your properties have setters in Account class.

How can I use ReadAsAsync<T> with this data schema?

I am using System.Net.Http.HttpClient, the version currently available in NuGet,
to retrieve data from a service in json format. The data roughly looks like this:
{
"schema": "Listing",
"data": {
"key": "28ba648c-de24-45d4-a7d9-70f810cf5438",
"children": [{
"kind": "type1",
"data": {
"body": "Four score and seven years ago...",
"parent_id": "2qh3l",
"report_count": 0,
"name": "c4j6yeh"
}
}, {
"kind": "type3",
"data": {
"domain": "abc.def.com",
"flagged": true,
"category": "news",
"saved": false,
"id": "t3dz0",
"created": 1335998011.0
}
}]
}
}
I use HttpContentExtensions.ReadAsAsync<T> to de-serialize that json string into an object graph. The type definitions looks roughly like this:
public class Response
{
public String schema { get;set; }
public ListingData data { get;set; }
}
public class ListingData
{
public string key { get;set; }
public List<OneItem> children { get;set; }
}
Here's the problem: I desire the type of the items in children to vary depending on the kind property. If kind is "type1" then I want to de-serialize an object of... let's call it Type1 . If kind is "type3" then I want an object of type Type3.
Right now, I can deserialize a List<Type1> or a List<Type3>, but I don't know how to tell the de-serialization logic to distinguish between the two.
I could merge all the properties of the "type1" data object and the "type3" data object into a single .NET Type. But the number of properties is large enough that this gets messy.
If the name of the property in the JSON (in this case data) were different, I could distinguish using that. If, for example, the data looked like this:
"children": [{
"kind": "type1",
"t1data": { ... }
}, {
"kind": "type3",
"t3data": { ... }
}]
...then I could do something like this in .NET:
public class OneItem
{
public string kind { get;set; }
public Type1 t1data { get;set; }
public Type3 t3data { get;set; }
}
But my data schema doesn't look like that.
Is it possible to choose the type for de-serialization by the content of the data? In other words,
look at the value of one property (in this case, kind) to determine how to de-serialize the content for another property (in this case, data).
Or is it possible to inject a filter or transformer that acts on the JSON before ReadAsAsync tries to deserialize it?
If so, How?
If you're ok w/ doing some pre-processing on your response and you can use Json.NET, you should be able to do what you want.
Given the following classes:
public class Response
{
public string schema
{
get;
set;
}
public ListingData data
{
get;
set;
}
}
public class ListingData
{
public string key
{
get;
set;
}
public List<object> children
{
get;
set;
}
}
public class Type1
{
public string body
{
get;
set;
}
public string parent_id
{
get;
set;
}
public int report_count
{
get;
set;
}
public string name
{
get;
set;
}
}
public class Type3
{
public string domain
{
get;
set;
}
public bool flagged
{
get;
set;
}
public string category
{
get;
set;
}
public bool saved
{
get;
set;
}
public string id
{
get;
set;
}
public double created
{
get;
set;
}
}
This test passes:
[Test]
public void RoundTrip()
{
var response = new Response
{
schema = "Listing",
data = new ListingData
{
key = "28ba648c-de24-45d4-a7d9-70f810cf5438",
children = new List<object>
{
new Type1
{
body = "Four score and seven years ago...",
parent_id = "2qh3l",
report_count = 0,
name = "c4j6yeh"
},
new Type3
{
domain = "abc.def.com",
flagged = true,
category = "news",
saved = false,
id = "t3dz0",
created = 1335998011.0
}
}
}
};
var jsonSerializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
TypeNameHandling = TypeNameHandling.Objects
};
string serializedResponse = JsonConvert.SerializeObject(response, jsonSerializerSettings);
Console.WriteLine(serializedResponse);
var roundTrippedResponse = JsonConvert.DeserializeObject<Response>(serializedResponse, jsonSerializerSettings);
Assert.That(roundTrippedResponse.data.children.First().GetType(), Is.EqualTo(typeof(Type1)));
Assert.That(roundTrippedResponse.data.children.Last().GetType(), Is.EqualTo(typeof(Type3)));
}
The output written to the console is:
{
"$type": "Test.Response, Test",
"schema": "Listing",
"data": {
"$type": "Test.ListingData, Test",
"key": "28ba648c-de24-45d4-a7d9-70f810cf5438",
"children": [
{
"$type": "Test.Type1, Test",
"body": "Four score and seven years ago...",
"parent_id": "2qh3l",
"report_count": 0,
"name": "c4j6yeh"
},
{
"$type": "Test.Type3, Test",
"domain": "abc.def.com",
"flagged": true,
"category": "news",
"saved": false,
"id": "t3dz0",
"created": 1335998011.0
}
]
}
}
So if you can transform your received response to match that of Json.NET's expected format, this will work.
To piece all of this together, you would need to write a custom MediaTypeFormatter and pass it to the ReadAsAsync<>() call.

Categories

Resources