How to create hierarchy in json string from string array? - c#

I am trying to generate json string for the hierarchy like below:
Company(select * from Company)
Department(select * from Department)
Employee(select * from Employee)
Each of the above query will return fields like below:
Company Fields - (Id,Name,Location)
Department Fields - (Id,Name,CompanyId)
Employee Fields - (Id,Name,DepartmentId)
Now I am trying to generate JSON string for above entities like below:
Expected output:
{
"Id": "",
"Name": "",
"Location": "",
"Department":
{
"Id": "",
"Name": "",
"CompanyId": "",
"Employee" :
{
"Id": "",
"Name": "",
"DepartmentId": "",
}
}
}
Code:
public string GetData(Child model,List<Parent> parents)
{
var fields = new List<string[]>();
if (parents != null)
{
foreach (var parent in parents)
{
var columns = GetColumns(parent); //returns string[] of columns
fields.Add(columns);
}
}
fields.Add(GetColumns(model));
string json = JsonConvert.SerializeObject(fields.ToDictionary(key => key, v => string.Empty),
Formatting.Indented);
return json;
}
Now when I don't have any parents and want to generate json string for only child then below code is working fine:
string json = JsonConvert.SerializeObject(fields.ToDictionary(key => key, v => string.Empty),Formatting.Indented)
Output :
{
"Id": "",
"Name": "",
"Location": "",
}
But now I want to generate JSON for my hierarchy with any such inbuilt way.
I know I can loop,append and create json string but I want to do this in better way like I have done for my child.
Update:
public class Child
{
public string Name { get; set; } // Contains Employee
//Other properties and info related to process sql query and connection string
}
public class Parent
{
public string Name { get; set; } // Contains Company,Department.
public string SqlQuery { get; set; } // query related to Company and Department.
//Other properties and info related to connection string
}

I created a class that holds the Information similarly to what you proposed, in a child-parent structure. I also added a custom little Parser that works recursively. Maybe that's what you need and/or what gives you the ideas you need to fix your problem.
I also altered the output a little bit, by adding the angled brackets ( "[ ]" ). I think that's what you will need with multiple children. At least that's what the JSON validator tells me that I posted below. If you don't need/ want them, just remove them in the parser.
I don't think you can use the parser you used in your example without having some form of extra fields like I showed in my previous answer, since those parsers usually go for property names as fields and I guess you don't want to create classes dynamically during runtime.
I also don't think that it is possible for you to create a dynamic depth of your parent-child-child-child...-relationship with Lists, Arrays or Dictionaries, because those structures have a set depth as soon as they are declared.
Class:
public class MyJsonObject
{
public List<string> Columns = new List<string>();
public string ChildName;
public List<MyJsonObject> Children = new List<MyJsonObject>();
}
Parser:
class JsonParser
{
public static string Parse(MyJsonObject jsonObject)
{
string parse = "{";
parse += string.Join(",", jsonObject.Columns.Select(column => $"\"{column}\": \"\""));
if (!string.IsNullOrEmpty(jsonObject.ChildName))
{
parse += $",\"{jsonObject.ChildName}\":";
parse += $"[{string.Join(",", jsonObject.Children.Select(Parse))}]";
}
parse += "}";
return parse;
}
}
Usage:
class Program
{
static void Main(string[] args)
{
MyJsonObject company = new MyJsonObject();
company.ChildName = "Department";
company.Columns.Add("Id");
company.Columns.Add("Name");
company.Columns.Add("Location");
MyJsonObject department = new MyJsonObject();
department.ChildName = "Employee";
department.Columns.Add("Id");
department.Columns.Add("Name");
department.Columns.Add("CompanyId");
MyJsonObject employee1 = new MyJsonObject();
employee1.Columns.Add("Id");
employee1.Columns.Add("Name");
employee1.Columns.Add("DepartmentId");
MyJsonObject employee2 = new MyJsonObject();
employee2.Columns.Add("Id");
employee2.Columns.Add("Name");
employee2.Columns.Add("DepartmentId");
company.Children.Add(department);
department.Children.Add(employee1);
department.Children.Add(employee2);
var json = JsonParser.Parse(company);
}
}
Output and Link to JSON-Validator:
https://jsonformatter.curiousconcept.com/
{
"Id":"",
"Name":"",
"Location":"",
"Department":[
{
"Id":"",
"Name":"",
"CompanyId":"",
"Employee":[
{
"Id":"",
"Name":"",
"DepartmentId":""
},
{
"Id":"",
"Name":"",
"DepartmentId":""
}
]
}
]
}

Perhaps I'm missing something. If you create the classes you need in the heirachy, instantiate them with data and then serialize them, the structure will be created for you.
using System.Web.Script.Serialization;
public class Employee
{
public int Id {get; set; }
public string Name {get; set; }
public int DepartmentId {get; set; }
}
public class Department
{
public int Id {get; set; }
public string Name {get; set; }
public string CompanyId {get; set; }
public List<Employee> {get; set;}
}
public class Company {
public int Id {get; set; }
public string Name {get; set; }
public string Location {get; set; }
public List<Department> {get; set;}
}
var myCompany = new Company();
// add departments and employees
var json = new JavaScriptSerializer().Serialize(myCompany);

You can use dynamic:
//here your database
dynamic[] company = new object[] { new { Name = "Company1", DepartmentId = 1 }, new { Name = "Company2", DepartmentId = 2 } };
dynamic[] department = new object[] { new { DepartmentId = 1, Name = "Department1" }, new { DepartmentId = 2, Name = "Department2" } };
//select from database
var data = from c in company
join d in department on c.DepartmentId equals d.DepartmentId
select new {Name = c.Name, Department = d};
var serialized = JsonConvert.SerializeObject(data);
result:
[
{
"Name": "Company1",
"Department": {
"DepartmentId": 1,
"Name": "Department1"
}
},
{
"Name": "Company2",
"Department": {
"DepartmentId": 2,
"Name": "Department2"
}
}
]

Ok, lets try like this. First of all as i understand your preblem: u have arrays of properties of parents and child and u neet to convert it to json object.
The point is here:
public static ExpandoObject DicTobj(Dictionary<string, object> properties)
{
var eo = new ExpandoObject();
var eoColl = (ICollection<KeyValuePair<string, object>>)eo;
foreach (var childColumn in properties)
eoColl.Add(childColumn);
return eo;
}
U use dynamic and ExpandoObject to convert dictionary to object
The other code is trivial: u put all your objects to one using dynamic type
and serialize it.
The full code:
public static Child Child1 { get; set; } = new Child
{
Name = "Child1"
};
public static Parent Parent1 { get; set; } = new Parent
{
Name = "Parent1"
};
public static Parent Parent2 { get; set; } = new Parent
{
Name = "Parent2"
};
private static void Main(string[] args)
{
var result = GetData(Child1, new List<Parent> {Parent1, Parent2});
Console.WriteLine(result);
}
/// <summary>
/// This is the magic: convert dictionary of properties to object with preperties
/// </summary>
public static ExpandoObject DicTobj(Dictionary<string, object> properties)
{
var eo = new ExpandoObject();
var eoColl = (ICollection<KeyValuePair<string, object>>) eo;
foreach (var childColumn in properties)
eoColl.Add(childColumn);
return eo;
}
public static string GetData(Child model, List<Parent> parents)
{
var childColumns = GetColumns(model);
dynamic child = DicTobj(childColumns);
var parentsList = new List<object>();
foreach (var parent in parents)
{
var parentColumns = GetColumns(parent);
var parentObj = DicTobj(parentColumns);
parentsList.Add(parentObj);
}
child.Parents = parentsList;
return JsonConvert.SerializeObject(child);
}
/// <summary>
/// this is STUB method for example
/// I change return type from string[] to Dictionary[columnName,ColumnValue], becouse u need not only column names, but
/// with it values, i gues. If not, look commented example at the end of this method
/// </summary>
public static Dictionary<string, object> GetColumns(object model)
{
var result = new Dictionary<string, object>();
if (model == Child1)
{
result.Add("Id", "1");
result.Add("Name", "Child1");
result.Add("Location", "SomeLocation");
}
if (model == Parent1)
{
result.Add("Id", "2");
result.Add("Name", "Parent1");
result.Add("SomeProperty1", "SomeValue1");
}
if (model == Parent2)
{
result.Add("Id", "3");
result.Add("Name", "Parent1");
result.Add("SomeProperty3", "SomeValue2");
}
//if u have only columNames and dont need values u can do like this
//var columns = new[] {"Id", "Name", "SomeProperty1"};//this u get from DB
//return columns.ToDictionary(c => c, c => new object());
return result;
}
}
public class Child
{
public string Name { get; set; } // Contains Employee
//Other properties and info related to process sql query and connection string
}
public class Parent
{
public string Name { get; set; } // Contains Company,Department.
public string SqlQuery { get; set; } // query related to Company and Department.
//Other properties and info related to connection string
}
And result output:
{
"Id": "1",
"Name": "Child1",
"Location": "SomeLocation",
"Parents": [
{
"Id": "2",
"Name": "Parent1",
"SomeProperty1": "SomeValue1"
},
{
"Id": "3",
"Name": "Parent1",
"SomeProperty3": "SomeValue2"
}
]
}

You can pass any kind of object even if you don't have a fixed structure:
Newtonsoft.Json.JsonConvert.SerializeObject(new yourCustomObject)
By using this.

The best way to to get this result
- You have to create a new class which has the relation of all the class. Then use the
Newtonsoft.Json.JsonConvert.SerializeObject(new organization )
Let creates a new class named organization . Add the relation which you want to see in Json. Then convert into the JSON using JsonConvert.
Or you can use the following dynamic loop
//here your database<br/>
dynamic[] company = new object[] { new { Name = "Company1", DepartmentId = 1 }, new { Name = "Company2", DepartmentId = 2 } };
dynamic[] department = new object[] { new { DepartmentId = 1, Name = "Department1" }, new { DepartmentId = 2, Name = "Department2" } };
//select from database<br/>
var data = from c in company
join d in department on c.DepartmentId equals d.DepartmentId
select new {Name = c.Name, Department = d};
var serialized = JsonConvert.SerializeObject(data);

Related

Want to create one list with one Id and multiple ProviderId values like

I want to create one list with one Id and multiple ProviderId values like
Id ProviderId
1 "val1"
1 "val2"
I have a model class as per below :
public class Model
{
[JsonProperty]
public string Id { get; set; }
[JsonProperty]
public List<PrefDictionary> ProviderId { get; set; }
}
Now I have created one list as per below :
List<PrefDictionary> PrefData = data.Select(p => new PrefDictionary()
{
_1 = p.PrefDictionary._1,
_2 = p.PrefDictionary._2
}).ToList();
Here in data I am getting whole json format data and one node is like this below for PrefDictionary.
data = {
Id : 1,
PrefDictionary{
1: "Val1",
2: "Val2"
}}
Now then I have created one more list as per below :
List<Model> PP = data.Select(p => new Model()
{
Id = p.Id,
ProviderId = PrefData.Select(x => new PrefDictionary()
{
_1 = x._1,
_2 = x._2
}).ToList(),
}).ToList();
}
But the problem is I am getting empty in second column list in first I am getting Id but not getting any value in second column.
I'm not 100% I understand JSON format you are expecting. However, if you want a list of providers - each with a list of preferences - then I think you'll need another class to get this to serialize properly:
public class Model
{
[JsonProperty]
public List<Providers> providers { get; set; }
}
public class Providers
{
[JsonProperty]
public string Id { get; set; }
[JsonProperty]
public List<PrefDictionary> ProviderId { get; set; }
}
This should give you the JSON output:
{
"Providers": [
{
"ID": 1,
"PrefDictionary": [
{
"Val1": "",
"Val2": ""
}
]
},
{
"ID": 2,
"PrefDictionary": [
{
"Val1": "",
"Val2": ""
}
]
}
]
}
I suspect the problem could be the way how you deserialize your data object.
Based on your code, I've created the result that contains the PrefDirectonary.
.
However, one thing I did for the data variable was to make an object like this,
PrefDictionary pd = new PrefDictionary
{
_1 = "Value1",
_2 = "Value2"
};
List<TestObject> data = new List<TestObject>() {
new TestObject
{
Id = "1",
PrefDictionary = pd
}
};
It will be helpful to show us how you deserialize the JSON data object.

need help on desired JSON output

I have below class structures,
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Message
{
public int Size { get; set; } = 10;
public Student Student { get; set; }
}
Now I have list of messages like,
var messages = new List<Message>
{
new Message{ Size=10, Student=new Student{Id=1, Name="N1" } },
new Message{ Size=20, Student=new Student{Id=2, Name="N2" } }
};
which I want to write in JSON using Newtonsoft.Json,
using (var f = File.CreateText("C:\\Temp\\test.json"))
{
f.Write(JsonConvert.SerializeObject(messages));
}
This give below JSON output,
[
{
"Size": 10,
"Student": {
"Id": 1,
"Name": "N1"
}
},
{
"Size": 20,
"Student": {
"Id": 2,
"Name": "N2"
}
}
]
But I would like below output (without size and only one time root element student),
{
"Student": [
{
"Id": 1,
"Name": "N1"
},
{
"Id": 2,
"Name": "N2"
}
]
}
whats need to be done here? Thanks!
You need to refine your data to get desired result
first
var refindedResult = new { Students = messages.Select(m => m.Student) };
second pass it to json convertor
using (var f = File.CreateText("C:\\Temp\\test.json"))
{
f.Write(JsonConvert.SerializeObject(refindedResult ));
}
You can try to write a StudentModel class.
public class StudentModel
{
public IEnumerable<Student> Student { get; set; }
}
use linq get student collection from messages, then SerializeObject on it.
var res = new StudentModel()
{
Student = messages.Select(x => x.Student)
};
var json = JsonConvert.SerializeObject(res);
//f.Write(JsonConvert.SerializeObject(messages));
f.Write(JsonConvert.SerializeObject(messages.Select(m => m.Student)));
or, when you want a root object (Students, not Student)
f.Write(JsonConvert.SerializeObject(
new { Students = messages.Select(m => m.Student) } ));

How can I create a JsonPatchDocument from comparing two c# objects?

Given I have two c# objects of the same type, I want to compare them to create a JsonPatchDocument.
I have a StyleDetail class defined like this:
public class StyleDetail
{
public string Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public decimal OriginalPrice { get; set; }
public decimal Price { get; set; }
public string Notes { get; set; }
public string ImageUrl { get; set; }
public bool Wishlist { get; set; }
public List<string> Attributes { get; set; }
public ColourList Colours { get; set; }
public SizeList Sizes { get; set; }
public ResultPage<Style> Related { get; set; }
public ResultPage<Style> Similar { get; set; }
public List<Promotion> Promotions { get; set; }
public int StoreStock { get; set; }
public StyleDetail()
{
Attributes = new List<string>();
Colours = new ColourList();
Sizes = new SizeList();
Promotions = new List<Promotion>();
}
}
if I have two StyleDetail objects
StyleDetail styleNew = db.GetStyle(123);
StyleDetail styleOld = db.GetStyle(456);
I now want to create a JsonPatchDocument so I can send the differences to my REST API... How to do this??
JsonPatchDocument patch = new JsonPatchDocument();
// Now I want to populate patch with the differences between styleNew and styleOld - how?
in javascript, there is a library to do this https://www.npmjs.com/package/rfc6902
Calculate diff between two objects:
rfc6902.createPatch({first: 'Chris'}, {first: 'Chris', last:
'Brown'});
[ { op: 'add', path: '/last', value: 'Brown' } ]
but I am looking for a c# implementation
Let's abuse the fact that your classes are serializable to JSON!
Here's a first attempt at a patch creator that doesn't care about your actual object, only about the JSON representation of that object.
public static JsonPatchDocument CreatePatch(object originalObject, object modifiedObject)
{
var original = JObject.FromObject(originalObject);
var modified = JObject.FromObject(modifiedObject);
var patch = new JsonPatchDocument();
FillPatchForObject(original, modified, patch, "/");
return patch;
}
static void FillPatchForObject(JObject orig, JObject mod, JsonPatchDocument patch, string path)
{
var origNames = orig.Properties().Select(x => x.Name).ToArray();
var modNames = mod.Properties().Select(x => x.Name).ToArray();
// Names removed in modified
foreach (var k in origNames.Except(modNames))
{
var prop = orig.Property(k);
patch.Remove(path + prop.Name);
}
// Names added in modified
foreach (var k in modNames.Except(origNames))
{
var prop = mod.Property(k);
patch.Add(path + prop.Name, prop.Value);
}
// Present in both
foreach (var k in origNames.Intersect(modNames))
{
var origProp = orig.Property(k);
var modProp = mod.Property(k);
if (origProp.Value.Type != modProp.Value.Type)
{
patch.Replace(path + modProp.Name, modProp.Value);
}
else if (!string.Equals(
origProp.Value.ToString(Newtonsoft.Json.Formatting.None),
modProp.Value.ToString(Newtonsoft.Json.Formatting.None)))
{
if (origProp.Value.Type == JTokenType.Object)
{
// Recurse into objects
FillPatchForObject(origProp.Value as JObject, modProp.Value as JObject, patch, path + modProp.Name +"/");
}
else
{
// Replace values directly
patch.Replace(path + modProp.Name, modProp.Value);
}
}
}
}
Usage:
var patch = CreatePatch(
new { Unchanged = new[] { 1, 2, 3, 4, 5 }, Changed = "1", Removed = "1" },
new { Unchanged = new[] { 1, 2, 3, 4, 5 }, Changed = "2", Added = new { x = "1" } });
// Result of JsonConvert.SerializeObject(patch)
[
{
"path": "/Removed",
"op": "remove"
},
{
"value": {
"x": "1"
},
"path": "/Added",
"op": "add"
},
{
"value": "2",
"path": "/Changed",
"op": "replace"
}
]
You could use my DiffAnalyzer. It's based on reflection and you can configure the depth you want to analyze.
https://github.com/rcarubbi/Carubbi.DiffAnalyzer
var before = new User { Id = 1, Name="foo"};
var after= new User { Id = 2, Name="bar"};
var analyzer = new DiffAnalyzer();
var results = analyzer.Compare(before, after);
You can use this
You can install using NuGet, see SimpleHelpers.ObjectDiffPatch at NuGet.org
PM> Install-Package SimpleHelpers.ObjectDiffPatch
Use:
StyleDetail styleNew = new StyleDetail() { Id = "12", Code = "first" };
StyleDetail styleOld = new StyleDetail() { Id = "23", Code = "second" };
var diff = ObjectDiffPatch.GenerateDiff (styleOld , styleNew );
// original properties values
Console.WriteLine (diff.OldValues.ToString());
// updated properties values
Console.WriteLine (diff.NewValues.ToString());

Create JSON with dynamic using newtonsoft json.net

I am trying to create or searealize json in this format
{
"title": "Star Wars",
"link": "http://www.starwars.com",
"description": "Star Wars blog.",
"item": [
{
"title": "Episode VII",
"description": "Episode VII production",
"link": "episode-vii-production.aspx"
},
{
"title": "Episode VITI",
"description": "Episode VII production",
"link": "episode-vii-production.aspx"
}
]
}
i am trying this achieve this
dynamic o = new ExpandoObject();
o.title= "fdsfs";
o.link= "fsrg";
o.description="fdsfs";
foreach (var adata in all)
{
o.item.title="fgfd";
o.item.description="sample desc";
o.item.link="http://google.com"
}
string json = JsonConvert.SerializeObject(o);
but than here it throws exception on foreach loop on item it tells it does not contain defination for the same etc .so what i am doing wrong and how to achieve the same
That is the construction you should have to get the json you've stated. The problem with your code is that item should be actually a list of items.
public class Item
{
public string title { get; set; }
public string description { get; set; }
public string link { get; set; }
}
public class RootObject
{
public string title { get; set; }
public string link { get; set; }
public string description { get; set; }
public List<Item> item { get; set; }
}
Then you ca use this code:
dynamic o = new ExpandoObject();
o.title= "fdsfs";
o.link= "fsrg";
o.description="fdsfs";
o.item = new List<ExpandoObject>();
//although list of dynamics is not recommended as far as I remember
foreach (var adata in all)
{
o.item.Add(new Item(){
title="fgfd",
description="sample desc",
link="http://google.com" });
}
string json = JsonConvert.SerializeObject(o);
You have to create o.item to assign values into it:
dynamic o = new ExpandoObject();
var all = new object[] { new object() };
o.title= "fdsfs";
o.link= "fsrg";
o.description="fdsfs";
var items = new List<ExpandoObject>();
foreach (var adata in all)
{
dynamic item = new ExpandoObject();
item.title="fgfd";
item.description="sample desc";
item.link="http://google.com";
items.Add(item);
}
o.item = items;
string json = JsonConvert.SerializeObject(o);

Json.NET serialize object with root name

In my web app I'm using Newtonsoft.Json and I have following object
[Newtonsoft.Json.JsonObject(Title = "MyCar")]
public class Car
{
[Newtonsoft.Json.JsonProperty(PropertyName = "name")]
public string Name{get;set;}
[Newtonsoft.Json.JsonProperty(PropertyName = "owner")]
public string Owner{get;set;}
}
and I want serialize them with root name (class name). This is desired format using
{'MyCar':
{
'name': 'Ford',
'owner': 'John Smith'
}
}
I know that I can do that with anonymous object, but is any property or another way in Newtonsoft.Json library?
Use anonymous class
Shape your model the way you want using anonymous classes:
var root = new
{
car = new
{
name = "Ford",
owner = "Henry"
}
};
string json = JsonConvert.SerializeObject(root);
I found an easy way to render this out... simply declare a dynamic object and assign the first item within the dynamic object to be your collection class...This example assumes you're using Newtonsoft.Json
private class YourModelClass
{
public string firstName { get; set; }
public string lastName { get; set; }
}
var collection = new List<YourModelClass>();
var collectionWrapper = new {
myRoot = collection
};
var output = JsonConvert.SerializeObject(collectionWrapper);
What you should end up with is something like this:
{"myRoot":[{"firstName":"John", "lastName": "Citizen"}, {...}]}
You can easily create your own serializer
var car = new Car() { Name = "Ford", Owner = "John Smith" };
string json = Serialize(car);
string Serialize<T>(T o)
{
var attr = o.GetType().GetCustomAttribute(typeof(JsonObjectAttribute)) as JsonObjectAttribute;
var jv = JValue.FromObject(o);
return new JObject(new JProperty(attr.Title, jv)).ToString();
}
Sorry, my english is not that good. But i like to improve the upvoted answers.
I think that using Dictionary is more simple and clean.
class Program
{
static void Main(string[] args)
{
agencia ag1 = new agencia()
{
name = "Iquique",
data = new object[] { new object[] {"Lucas", 20 }, new object[] {"Fernando", 15 } }
};
agencia ag2 = new agencia()
{
name = "Valparaiso",
data = new object[] { new object[] { "Rems", 20 }, new object[] { "Perex", 15 } }
};
agencia agn = new agencia()
{
name = "Santiago",
data = new object[] { new object[] { "Jhon", 20 }, new object[] { "Karma", 15 } }
};
Dictionary<string, agencia> dic = new Dictionary<string, agencia>
{
{ "Iquique", ag1 },
{ "Valparaiso", ag2 },
{ "Santiago", agn }
};
string da = Newtonsoft.Json.JsonConvert.SerializeObject(dic);
Console.WriteLine(da);
Console.ReadLine();
}
}
public class agencia
{
public string name { get; set; }
public object[] data { get; set; }
}
This code generate the following json (This is desired format)
{
"Iquique":{
"name":"Iquique",
"data":[
[
"Lucas",
20
],
[
"Fernando",
15
]
]
},
"Valparaiso":{
"name":"Valparaiso",
"data":[
[
"Rems",
20
],
[
"Perex",
15
]
]
},
"Santiago":{
"name":"Santiago",
"data":[
[
"Jhon",
20
],
[
"Karma",
15
]
]
}
}
string Json = JsonConvert.SerializeObject(new Car { Name = "Ford", Owner = "John Smith" }, Formatting.None);
for the root element use GlobalConfiguration.
A very simple approach for me is just to create 2 classes.
public class ClassB
{
public string id{ get; set; }
public string name{ get; set; }
public int status { get; set; }
public DateTime? updated_at { get; set; }
}
public class ClassAList
{
public IList<ClassB> root_name{ get; set; }
}
And when you going to do serialization:
var classAList = new ClassAList();
//...
//assign some value
//...
var jsonString = JsonConvert.SerializeObject(classAList)
Lastly, you will see your desired result as the following:
{
"root_name": [
{
"id": "1001",
"name": "1000001",
"status": 1010,
"updated_at": "2016-09-28 16:10:48"
},
{
"id": "1002",
"name": "1000002",
"status": 1050,
"updated_at": "2016-09-28 16:55:55"
}
]
}
Hope this helps!
Well, you can at least tell Json.NET to include the type name: http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_TypeNameHandling.htm . Newtonsoft.Json.JsonSerializer jser = new Newtonsoft.Json.JsonSerializer();
jser.TypeNameHandling = TypeNameHandling.Objects;
The type will be included at the beginning in the "$type" property of the object.
This is not exactly what you are looking for, but it was good enough for me when facing a similiar problem.
Writing a custom JsonConverter is another approach mentioned in similar questions. However, due to nature of how JsonConverter is designed, using that approach for this question is tricky, as you need to be careful with the WriteJson implementation to avoid getting into infinite recursion: JSON.Net throws StackOverflowException when using [JsonConvert()].
One possible implementation:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
//JToken t = JToken.FromObject(value); // do not use this! leads to stack overflow
JsonObjectContract contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType());
writer.WriteStartObject();
writer.WritePropertyName(value.GetType().Name);
writer.WriteStartObject();
foreach (var property in contract.Properties)
{
// this removes any property with null value
var propertyValue = property.ValueProvider.GetValue(value);
if (propertyValue == null) continue;
writer.WritePropertyName(property.PropertyName);
serializer.Serialize(writer, propertyValue);
//writer.WriteValue(JsonConvert.SerializeObject(property.ValueProvider.GetValue(value))); // this adds escaped quotes
}
writer.WriteEndObject();
writer.WriteEndObject();
}
I hope this help.
//Sample of Data Contract:
[DataContract(Name="customer")]
internal class Customer {
[DataMember(Name="email")] internal string Email { get; set; }
[DataMember(Name="name")] internal string Name { get; set; }
}
//This is an extension method useful for your case:
public static string JsonSerialize<T>(this T o)
{
MemoryStream jsonStream = new MemoryStream();
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T));
serializer.WriteObject(jsonStream, o);
var jsonString = System.Text.Encoding.ASCII.GetString(jsonStream.ToArray());
var props = o.GetType().GetCustomAttributes(false);
var rootName = string.Empty;
foreach (var prop in props)
{
if (!(prop is DataContractAttribute)) continue;
rootName = ((DataContractAttribute)prop).Name;
break;
}
jsonStream.Close();
jsonStream.Dispose();
if (!string.IsNullOrEmpty(rootName)) jsonString = string.Format("{{ \"{0}\": {1} }}", rootName, jsonString);
return jsonString;
}
//Sample of usage
var customer = new customer {
Name="John",
Email="john#domain.com"
};
var serializedObject = customer.JsonSerialize();
[Newtonsoft.Json.JsonObject(Title = "root")]
public class TestMain
this is the only attrib you need to add to get your code working.

Categories