Serializing and deserializing objects with arbitrary fields using Json.NET in Unity - c#

I'd like to serialize and deserialize objects with arbitrary fields. I've tried to have the object with the arbitrary fields extend Dictionary<string, object> in hopes that I would be able to set the arbitrary fields as Dictionary entries. In this case I expect to have Company and Position in the json response (listed in code comments) in addition to the manager and office fields. Unfortunately I'm able get the arbitrary fields but unable to get the non arbitrary fields.
I would also like to be able to add arbitrary objects, not just strings (ie add a salary object with base salary, bonus, etc to the job). I also have some restrictions and cannot use dynamic for this.
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Job Job { get; set; }
}
public class Job : Dictionary<string, object>
{
public string Company { get; set; }
public string Position { get; set; }
}
var job = new Job()
{
Company = "Super Mart",
Position = "Cashier"
};
// Set arbitrary fields
job["manager"] = "Kathy";
job["office"] = "001";
var john = new Person()
{
Name = "John Doe",
Age = 41,
Job = job
};
var employeeJson = JsonConvert.SerializeObject(john, Formatting.Indented);
Log.Debug("TestSerialization", "json: {0}", employeeJson);
// Result
// {
// "Name": "John Doe",
// "Age": 41,
// "Job": {
// "manager": "Kathy",
// "office": "001"
// }
// }
var johnDoe = JsonConvert.DeserializeObject<Person>(employeeJson);
Log.Debug("TestSerialization", "name: {0}, age: {1}", johnDoe.Name, johnDoe.Age);
// Result
// name: John Doe, age: 41
Log.Debug("TestSerialization", "company: {0}, position: {1}", johnDoe.Job.Company, johnDoe.Job.Position);
// Result
// company: , position:
Log.Debug("TestSerialization", "manager: {0}, office: {1}", johnDoe.Job["manager"], johnDoe.Job["office"]);
// Result
// manager: Kathy, office: 001
My result json from deserialization using this code is
{
"Name": "John Doe",
"Age": 41,
"Job": {
"manager": "Kathy",
"office": "001"
}
}
I would like the result json to be (what the service would expect)
{
"Name": "John Doe",
"Age": 41,
"Job": {
"Company" = "Super Mart",
"Position" = "Cashier"
"manager": "Kathy",
"office": "001"
}
}

I think the problem with your job Class, it derived from a dictionary so when you serialize it will not consider its members. only dictionary values,
Try this way, I am not sure this will help your context
public class Job
{
public string Company { get; set; }
public string Position { get; set; }
public Dictionary<string,object> job { get; set; }
public Job()
{
job = new Dictionary<string, object>();
}
}
Debug.Log(johnDoe.Job.job["manager"]+"-"+ johnDoe.Job.job["office"]);

Related

Parsing json file in c# to get into all sections and properties

==========Update
So in trying to phrase the issue properly, I have misled the responders in not giving me the answer I need. Apologies, let me try to clarify.
I need to be able to cycle through a json file that is not as structured as I indicated in the OP, it is much more random. The OP file did not convey that very well.
Let me try to describe what is closer to the file I'll be getting. The first two levels will be fixed, I'll call them LevelA and LevelB. But the properties in LevelB can be any pair of random data. This is a better json file example:
{
"LevelA": {
"LevelB": [
{
"EmpName": "John",
"EmpGender": "Male",
"Age": "25"
},
{
"FavoriteFood": "Beer",
"BaseballTeam": "Kansas City Royals"
},
{
"Red": "10",
"Blue": "40",
"White: "True"
}
]
}
}
Say I need to write out the following to console:
A LevelB entry has these properties:
Property: EmpName, Value: John
Property: EmpGender, Value: Male
Property: Age, Value: 25
A LevelB entry has these properties:
Property: FavoriteFood, Value: Beer
Property: BaseballTeam, Value: Kansas City Royals
A LevelB entry has these properties:
Property: Red, Value: 10
Property: Blue, Value: 40
Property: White, Value: True
It may not make sense but, I need to find a way to do that, I need that knowledge. I appreciate the answers about using a model, but I don't see a way to use a model without complicating what I think should be a simple task. Although not simple enough for me to figure out apparently. :)
==========
C#, VS 2019, a .NET framework console test app. I'm looking to do something simple but I can't find the right syntax.
I have a json file with the following structure. I want to loop through each Employee below and get at its properties (name, gender, etc...):
{
"Company": {
"Employees": [
{
"EmpName": "John",
"EmpGender": "Male",
"Age": "25"
},
{
"EmpName": "Mary",
"EmpGender": "Female"
},
{
"EmpName": "Bill",
"Age": "30"
}
]
}
}
First question is which package will do the job? I've installed Microsoft.Extensions.Configuration.Json and System.Configuration.ConfigurationManager but am having difficulties getting the syntax correct. Are these the right packages to use? I decided to use those because I thought I could load the file via ConfigurationBuilder and that the GetSection and/or GetChildren methods would help me. I can load the file but I can't figure out how to use those methods to give me what I want.
Second I don't want to build a model for this, I just want at the data. If I can get each employee into a dictionary, I can analyze that, and that would get me going. Thanks for any advice.
You can use the built-in JSON library in the .net core
using System.Text.Json;
add the following model definition
public class Rootobject
{
public Company Company { get; set; }
}
public class Company
{
public Employee[] Employees { get; set; }
}
public class Employee
{
public string EmpName { get; set; }
public string EmpGender { get; set; }
public string Age { get; set; }
}
deserialize your object like the following
string jsonData = File.ReadAllText("data.json");
Rootobject ob = JsonSerializer.Deserialize<Rootobject>(jsonData);
now you have ob in you c# represent your JSON as C# object
I don't want to build a model for this
if you use Visual Studio you can auto generate your model classes required for your JSON as described here the above models are auto generated by Visual Studio
If you don't want to create a model,and get a List<Dictionary<string,string>>,you can use custom model binding,here is a demo:
CustomBinder:
public class CustomBinder:IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var model = new List<Dictionary<string, string>>();
using (var reader = new StreamReader(bindingContext.HttpContext.Request.Body))
{
var body = reader.ReadToEndAsync();
var mydata = JsonConvert.DeserializeObject<JObject>(body.Result);
var s = mydata["Company"]["Employees"].ToString();
var list=JsonConvert.DeserializeObject<List<JObject>>(s);
foreach (var jobj in list) {
Dictionary<string, string> d = new Dictionary<string, string>();
foreach (var x in jobj)
{
string name = x.Key;
string value = x.Value.ToString();
d.Add(x.Key, x.Value.ToString());
}
model.Add(d);
}
}
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
Action:
public void TestJson1([ModelBinder(BinderType = typeof(CustomBinder))] List<Dictionary<string, string>> jsondata)
{
}
result:
Why is it a requirement not to build models? In my opinoin that is the easiest way and if you need to expand due to JSON changes, you can easily adapt it in the code. I paste a sample code here what is using System.Text.Json namespace (no other packages are also required due to it is built-in).
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace jsontest
{
class Program
{
static void Main(string[] args)
{
string input = "{ \"Company\": { \"Employees\": [{ \"EmpName\": \"John\", \"EmpGender\": \"Male\", \"Age\": \"25\" }, { \"EmpName\": \"Mary\", \"EmpGender\": \"Female\" }, { \"EmpName\": \"Bill\", \"Age\": \"30\" }]}}";
var processedInput = JsonSerializer.Deserialize<Company>(input);
foreach (var item in processedInput.Peoples.PeopleList)
{
Console.WriteLine($"{item.Name} - {item.Gender} - {item.Age}");
}
}
}
public class Employee
{
[JsonPropertyName("EmpName")]
public string Name { get; set; }
[JsonPropertyName("EmpGender")]
public string Gender { get; set; }
[JsonPropertyName("Age")]
public string Age { get; set; }
}
public class Employees
{
[JsonPropertyName("Employees")]
public List<Employee> PeopleList { get; set; }
}
public class Company
{
[JsonPropertyName("Company")]
public Employees Peoples { get; set; }
}
}
Update after your update:
Strange why you store data in JSON on this way. I wrote a quick code, it is using regex and some built-in function to parse the text. At the end result is similar what you would prefer. Code is a bit long, but only because I put some comment to make understanding easier.
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace jsontest
{
class Program
{
static void Main(string[] args)
{
List<List<ListItem>> result = new List<List<ListItem>>();
string input = "{ \"Company\": { \"Employees\": [{ \"EmpName\": \"John\", \"EmpGender\": \"Male\", \"Age\": \"25\" }, { \"EmpName\": \"Mary\", \"EmpGender\": \"Female\" }, { \"EmpName\": \"Bill\", \"Age\": \"30\" }]}}";
// Remove new lines, so input will become one single line
input = input.Replace(Environment.NewLine, " ");
// 1. group is the group name (in this case Employees)
// 2. group is the content after group name
string pattern1 = #"[{].+[{](.+)[\[](.+)[\]]";
foreach (System.Text.RegularExpressions.Match m in System.Text.RegularExpressions.Regex.Matches(input, pattern1))
{
// groupName -> "Employees":
string groupName = m.Groups[1].Value;
// groupName -> Employees
groupName = groupName.Substring(0, groupName.LastIndexOf("\""));
groupName = groupName.Substring(groupName.IndexOf("\"") + 1);
// contentList -> { "EmpName": "John", "EmpGender": "Male", "Age": "25" }, { "EmpName": "Mary", "EmpGender": "Female" }, { "EmpName": "Bill", "Age": "30" }
string contentList = m.Groups[2].Value;
// Split the line onto more lines where "}," characters
// { "EmpName": "John", "EmpGender": "Male", "Age": "25"
// { "EmpName": "Mary", "EmpGender": "Female"
// { "EmpName": "Bill", "Age": "30" }
string[] contentItems = contentList.Split("},");
foreach (var item in contentItems)
{
// Check every group and store them in separate list
result.Add(new List<ListItem>());
string[] keys = item.Split(",");
foreach (var key in keys)
{
// Check every Key-Value pair and store their value in the current list
string pattern2 = "[\"](.+)[:].[\"](.+)[\"]";
foreach (System.Text.RegularExpressions.Match m2 in System.Text.RegularExpressions.Regex.Matches(key, pattern2))
{
result[result.Count - 1].Add(new ListItem() { Property = groupName, Key = m2.Groups[1].Value.Substring(0, m2.Groups[1].Value.Length - 1), Value = m2.Groups[2].Value });
}
}
}
}
for (int i = 0; i < result.Count; i++)
{
for (int j = 0; j < result[i].Count; j++)
{
if (j == 0)
Console.WriteLine($"A {result[i][j].Property} entry has these properties:");
Console.WriteLine($"Proprty: {result[i][j].Key}, Value: {result[i][j].Value}");
}
}
}
}
class ListItem
{
public string Property { get; set; }
public string Key { get; set; }
public string Value { get; set; }
}
}
Output of this code is:
A Employees entry has these properties:
Proprty: EmpName, Value: John
Proprty: EmpGender, Value: Male
Proprty: Age, Value: 25
A Employees entry has these properties:
Proprty: EmpName, Value: Mary
Proprty: EmpGender, Value: Female
A Employees entry has these properties:
Proprty: EmpName, Value: Bill
Proprty: Age, Value: 30

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

Is it possible to skip object name during Json Serialization?

I have the below properties of an object:
public string SenderAccount { get; set; }
public string ReceiverAccount { get; set; }
public decimal Amount { get; set; }
public string Currency { get; set; }
public Info Info { get; set; }
And I want to have an output like this:
{ "sender_account":"1753154",
"receiver_account":"1753242",
"amount":15,
"currency":"USD",
"test":1,
"key":"_MERCHANT_KEY_",
"ts":_TIMESTAMP_,
"sign":"_SIGN_"
}
Where test,key,ts and sign, belong to Info object.
Now I want to skip this part:
1."Info":
2.{
3. "test":0,
4. "key":"mkey",
5. "ts":time_stamp,
6. "sign":"signature"
7.}
But to output only Info variables.
Reason is that from api documentation provided they use all time those Info variables to request.
Edit: I need to skip rows 1,2,7 during serialization.
You can do it like:
Object1 object1 = new Object1
{
sender_account = "1753154",
receiver_account = "1753242",
amount = 15,
currency = "USD",
Info = new Info
{
test = 1,
key = "_MERCHANT_KEY_",
ts = "_TIMESTAMP_",
sign = "_SIGN_"
}
};
And serialize it like:
var resultJson = JsonConvert.SerializeObject(new
{
object1.sender_account,
object1.receiver_account,
object1.amount,
object1.currency,
object1.Info.test,
object1.Info.key,
object1.Info.ts,
object1.Info.sign,
});
Output:
{
"sender_account": "1753154",
"receiver_account": "1753242",
"amount": 15,
"currency": "USD",
"test": 1,
"key": "_MERCHANT_KEY_",
"ts": "_TIMESTAMP_",
"sign": "_SIGN_"
}

Newtonsoft json deserialization - key as property

I have a json file :
...
"Key1": {
"Base": 123,
"Max": 1234
},
"Key2": {
"Base": 123,
"Max": 1234
},
"Key3": {
"Base": 123,
"Max": 1234
},
...
I need to deserialize it into an object with JsonConvert.DeserializeObject<T>(__json);
But I need to use the keys (Key1, Key2, Key3,...) as a property of my deserialized object.
Unfortunately, I can't use an alternate deserialization method and I can't modify the json format.
My object is like that
public class Item {
public string Id { get; set; }
public int Base { get; set; }
public int Max { get; set; }
}
My Id's should be "Key1", "Key2, ...
is it possible?
Make a custom Key class:
public class Key {
public int Base { get; set; }
public int Max { get; set; }
}
Then store each item in the JSON result in a Dictionary where it's key is the key name and it's value is a Key item:
var keyCollection = new Dictionary<string, Key>();
//you can then do stuff such as:
var maxOfKeyOne = keyCollection["Key1"].Max;
var baseOfKeyTwo = keyCollection["Key2"].Base;

C# dynamic Parsing search result from C# Facebook sdk issue

Trying to execute search on Facebook for pages
if (sq.ObjectType.Equals("page"))
{
searchPath = "/search";
req.q = sq.Query;
req.type = sq.ObjectType;
}
dynamic results = FBClient_.Get(req);
And I can't figure out how to parse results.
I cant just simple loop through them.
and I can't see the structure either since it's dynamic object
Somewhere down the line it has this structure:
{
"data": [
{
"name": "Platform-3",
"category": "Health/medical/pharmacy",
"id": "362034114769"
},
{
"name": "Platform Expos",
"category": "Product/service",
"id": "521000451259682"
},
{
"name": "eXo Platform",
"category": "Software",
"id": "152603664817327"
},
{
"name": "Platform 28",
"category": "Bar",
"id": "104411956289378"
},
}
but how to get it I'm not sure. How do I convert it into readable format?
Here are some mappings.
objects => IDictionary<string, object> or IDictionary<string, dynamic>
arrays => IList<object> or IList<dynamic>
number => long if whole number, double if have decimal values
string => string
boolean => bool
So in your case you could do this.
dynamic result = fb.Get("...")
foreach(var data in result.data) {
var name = data.name;
var category = data.category;
var id = data.id
}
Since result.data is dynamic which is actually IList<object> you can use foreach on it. You could also try this too.
dynamic result = fb.Get("...")
IList<dynamic> data = result.data;
foreach(var d in data) {
string name = d.name;
string category = d.category;
string id = d.id
}
Or you strongly typed.
public class SearchResults {
public IList<SearchResult> data { get; set;}
}
public class SearchResult {
public string id { get; set; }
public string name { get; set; }
public string category { get; set; }
}
var result = fb.Get<SearchResults>(...)
If you want to follow C# naming standards use DataContract and DataMember.
[DataContract]
public class SearchResults {
[DataMember(Name = "data")]
public IList<SearchResult> Data { get; set;}
}
[DataContract]
public class SearchResult {
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "Name")]
public string Name { get; set; }
[DataMember(Name = "Category")]
public string Category { get; set; }
}
You would either have to create strongly typed classes to represent your JSON data as prabir has posted, or you could use a JSON library such as Json.NET which will allow you to interact with your data much more easily. Here is an example from their page:
string json = #"{
""Name"": ""Apple"",
""Expiry"": new Date(1230422400000),
""Price"": 3.99,
""Sizes"": [
""Small"",
""Medium"",
""Large""
]
}";
JObject o = JObject.Parse(json);
string name = (string)o["Name"];
// Apple
JArray sizes = (JArray)o["Sizes"];
string smallest = (string)sizes[0];

Categories

Resources