In my POCO objects, I often inherit from other POCO objects. When I serialize a POCO object using JSON.NET, the order of properties gets all messed up.
Say, I have a Person class that looks like this:
public class Person
{
public int Id {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
}
Then I have an Employee class that inherits from Person class:
public class Employee : Person
{
public int DepartmentId {get; set;}
public string Title {get; set;}
}
When I serialize the Employee class, my JSON object looks like this:
{
"departmentId": 123,
"title": "Manager",
"id": 1234567,
"firstName": "John",
"lastName": "Smith"
}
Two questions:
Does the order of my JSON object properties matter?
Even if the order of properties doesn't matter, how can I get the properties to be in correct order i.e. I'd like to see the Person class properties first, then the Employee class properties.
Thank you for your help.
1.) No, order doesn't matter.
2.) You can use the [JsonProperty(Order=x)] attribute to control the order:
public class Employee : Person
{
[JsonProperty(Order = 1)]
public int DepartmentId { get; set; }
[JsonProperty(Order = 1)]
public string Title { get; set; }
}
From a quick test, order defaults to 0, is sorted from low to high, and properties with the same value of Order are sorted in an arbitrary order.
Actually, since my Object was already a JObject, I Had to use the following solution:
public class SortedJObject : JObject
{
public SortedJObject(JObject other)
{
var pairs = new List<KeyValuePair<string, JToken>>();
foreach (var pair in other)
{
pairs.Add(pair);
}
pairs.OrderBy(p => p.Key).ForEach(pair => this[pair.Key] = pair.Value);
}
}
and then use it like this:
string serializedObj = JsonConvert.SerializeObject(new SortedJObject(dataObject));
Related
I have a JSON string which can contain multiple students and teachers. An example is shown below. I want to deserialize the JSON into separate lists based on whether it contains a particular attribute.
[
{
"School": "St.Xavier"
},
{
"teacherid": 1,
"name": "Prof.Xavier",
"position": "Professor",
"class": "elite"
},
{
"studentid": 1,
"name": "QuickSilver",
"ability": "Rush",
"class": "elite"
}
]
For example:
List<Teacher> teacherList = JsonConvert.Deserialize<Teacher>(json);
List<Student> studentList = JsonConvert.Deserialize<Student>(json);
During deserialization, school info will be ignored, and each list will contain only those items with attributes matching according to the class. So teacherList will contain only teacher info, and studentList will contain only student info.
public class Teacher
{
[JsonProperty("teacherid")]
public string TeacherID {get;set;}
[JsonProperty("name")]
public string Name {get;set;}
[JsonProperty("position")]
public string Position {get;set;}
[JsonProperty("class")]
public string InCharge {get;set;}
}
public class Student
{
[JsonProperty("studentid")]
public string StudentID {get;set;}
[JsonProperty("name")]
public string Name {get;set;}
[JsonProperty("ability")]
public string Ability {get;set;}
[JsonProperty("class")]
public string Enrolled {get;set;}
}
How can I do this?
You can make a simple helper method to do what you want:
public static List<T> Deserialize<T>(string json, string attribute)
{
return JArray.Parse(json)
.Children<JObject>()
.Where(jo => jo[attribute] != null)
.Select(jo => jo.ToObject<T>())
.ToList();
}
Then use it like this:
List<Teacher> teachers = Deserialize<Teacher>(json, "teacherid");
List<Student> students = Deserialize<Student>(json, "studentid");
Fiddle: https://dotnetfiddle.net/aXQ99x
I have a class like so:
public class CareTaker
{
public int Id {get; set;}
public string name {get; set;}
public DateTime? DateTrained {get; set;}
public Certification Certification {get; set;}
public List<Certification> ExpiredCertifications {get; set;}
}
public class Certification
{
public int Id {get; set;}
}
and my JSON is like so:
{
"id": 1,
"name": "Dogtor",
"dateTrained": "01 Feb 2017",
"certification": 2,
"expiredCertifications": [1,5]
}
I know usually the JSON for Certification should really be like "certification": { "id": 2}, but, I don't have access to change the JSON so I have to figure out how to convert what I recieve ("certification": 2) to my object... Is there a way I can do this with either JavascriptSerializer or NewtonSoft please?
You could do something like this:
public class CareTaker
{
...
[NotMapped]
[JsonProperty(PropertyName = "certification"]
public int? CertificationId
{
get
{
return Certification?.Id;
}
set
{
Certification = new Certification { Id = value; }
}
}
[JsonIgnore]
public Certification Certification {get; set;}
...
}
To generate properly the classes, I would suggest copying the JSON and open the file where you want to store the classes and in visual studio go to EDIT->Paste Special->Paste JSON As Classes
then you would do something like this:
JavaScriptSerializer ser = new JavaScriptSerializer();
var jsonToClasses = ser.Deserialize<RootObject>(json);
I'm using json.net to serialize my responses to the client
I'm building a controller action (in mvc) that produce a json string from types of objects
so it looks something like this:
string json = JsonConvert.SerializeObject(Activator.CreateInstance(type));
my problem is that when an object has an object inside of it (complex type), the activator assign null to it and then, the Json serializer doesn't serialize it at all
for example
if my object class looks like this:
public class Phone
{
public string Name {get; set;}
public Model Model {get; set;}
}
public class Model
{
public string Name {get; set;}
public string IMEI {get; set;}
}
the json string will be:
{"Name":null, "Model":null}
so is there a way to make be:
{"Name":null, "Model":{"Name":null, "IMEI":null}}
thank you all for your answers
OK
it took me some time to write this answer (stack overflow restriction) but i've found a great way to do it with reflection and recurssion I've created this method:
public void CreateFullInstance(object obj)
{
PropertyInfo[] properties = obj.GetType().GetProperties();
foreach(var property in properties)
{
Type propertyType = property.PropertyType;
if(!propertyType.IsPrimitive &&
propertyType.GetConstructor(Type.EmptyTypes) != null)
{
var val = Activator.CreateInstance(propertyType);
property.SetValue(obj,val);
CreateFullInstance(val);
}
}
}
when I call it, I just pass my initial:
var phone = Activator.CreateInstance(propertyType);
CreateFullInstance(phone);
var json = JsonConvert.SerializeObject(phone);
the downside for this method is that objects with no empty constructor will be ignored. I think I can fix that but then again as I said, these are POCO models so they all have empty constructors
You need to initialize Model in the constructor of Phone object.
public class Phone
{
public Phone()
{
Model = new Model();
}
public string Name {get; set;}
public Model Model {get; set;}
}
public class Model
{
public string Name {get; set;}
public string IMEI {get; set;}
}
You can also use the Activator.CreateInstance overload by which you can pass values as parameters to the constructor of a type.
Using Activator you are creating the object of main class that's why after serializing json string contain entries for properties of the class...{"Name":null, "Model":null}
Now if you want property names of Model class properties as well in the json string, then odo something because of which your inner class get initialized...
We can achieve it in two ways
1)In constructor of Phone class initialize Model class follows.
public class Phone
{
public Phone()
{
Model = new Model();
}
public string Name {get; set;}
public Model Model {get; set;}
}
2)
MyClassObject obj = (MyClassObject)Activator.CreateInstance(type);
obj.Model=new Model();
hope it helped
How can we hide the C# property where serializing with JSON.NET library. Suppose, we have class Customer
public class Customer
{
public int CustId {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
public bool isLocked {get; set;}
public Customer() {}
}
public class Test
{
Customer cust = new Customer();
cust.CustId = 101;
cust.FirstName = "John"
cust.LastName = "Murphy"
string Json = JsonConvert.SerializeObject(cust);
}
JSON
{
"CustId": 101,
"FirstName": "John",
"LastName": "Murphy",
"isLocked": false
}
This object is converted to json, but i didn't specify the isLocked property. As library will serialize the entire class, is there any way to ignore a property during json serialization process or if we can add any attribute on the property.
EDIT:
Also, If we create two instance of Customer class in an array. if we didn't specify is locked property on the second instance, can we can property hide for second object.
JSON
{
"Customer": [
{
"CustId": 101,
"FirstName": "John",
"LastName": "Murphy",
"isLocked": false
},
{
"CustId": 102,
"FirstName": "Sara",
"LastName": "connie"
}
]
}
Use the JSON.Net attributes:
public class Customer
{
public int CustId {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
[JsonIgnore]
public bool isLocked {get; set;}
public Customer() {}
}
For more information: https://www.newtonsoft.com/json/help/html/SerializationAttributes.htm
Yes, marking your properties with JsonIgnore is probably best.
However, if you do want to chose at runtime, add a public bool ShouldSerialize{MemberName} to your class. When JSON.net Serialises it will call it, and if false, not serialise. isLocked is false by default, perhaps you do want to serialise it when its true, for example.
Mark that property with the JsonIgnore attribute.
I have these entities:
public class Product
{
public string Code {get;set;}
public string Name {get;set;}
public ICollection<Pack> Packs {get;set;}
}
public class Pack
{
public string Colour {get;set;}
public string Moq {get;set;}
}
my json object:
var products = [{
code: 1243123,
name: "Gel",
packs: [{
color: "blue",
moq: 10
}]
}];
note the naming differences, i.e. case and american spelling of color. Will the JavaScriptConvert.DeserializeObject() deserialise that correctly?
Or will I have to do it another way?
If I can just have an object where I can access those names directly and there values that would be great!
If you use something like JSON.NET, then you can use attributes to control serialization, such as:
public class Pack
{
[JsonProperty("color")]
public string Colour {get;set;}
[JsonProperty("moq")]
public string Moq {get;set;}
}
Also, given your expected output, your Product class should look like this I think:
public class Product
{
[JsonProperty("code")]
public long Code {get;set;}
[JsonProperty("name")]
public string Name {get;set;}
[JsonProperty("packs")]
public Pack[] Packs {get;set;}
}
Note Code and Packs type.
If you use DataContractJsonSerializer instead, you can put attributes to your properties, giving them different names in generated/parsed JSON:
[DataContract]
public class Pack
{
[DataMember(Name = "color")]
public string Colour {get;set;}
[DataMember(Name = "moq")]
public string Moq {get;set;}
}