Introduction
Attribute & inheritance, missing fields. two way conversion
Newtonsoft.Json is C# JSON serializer and deserializer library for .NET platform (including .NET Framework and .NET Core). Inside the implementation, it provides two layers of json handling class.
At the top: JsonCovert is a simple wrapper that allows to convert JSON from object and string
At the bottom: JsonSerializer allows to read/write json from/to stream, setup formatter converters, e.g. JavaScriptDateTimeConverter()
Serialization: from an object to a string, Deserialization: from a string to an object
-
Handler
Handlers are used when encountering different conditions, e.g. 1). a field that is not defined in object but is given in json string, 2). how to handle date string.
-
Default converting
C# JSON string, Type, Guid string Byte[] string (base64 encoded) DateTime string byte, int, float... number Enum number bool boolean IEnumerable (list, collection, array) array Dictionary, object object -
Serialization (from object to json)
1). Which field/Property should be serialized? Controlled by JsonObjectAttribute
public enum MemberSerialization{ // All public fields/properties are serialized. Members can be excluded using JsonIgnoreAttribute OptOut = 0, // default // All public fields/properties marked with JsonPropertyAttribute are serialized OptIn = 1, // all public, private fields are serialized. Properties are also serialized with weired names. Fields = 2 } [JsonObject(MemberSerialization.OptOut)] public class Person{ /*...*/}
2). How to control the name of each field/property on json? The name is first controlled by JsonProperty, and then by the field/property name itself.
JsonProperty indicates
1). this field/properties should be include in JSON even if it isn't public,
2). with assigning an optional name,
3). with a customized JsonConverter,
4). order in json
public class Person{ public string LastName {get; set;} [JsonProperty("firstname", Order = 1)] public string FirstName; }
{ "LastName":"Qin", "firstname": "Nan" }
3). Default value handling: when serializing, an object's field/property can be/not be ignored if it's value is the type's default value (e.g. null, 0). When deserializing set members to their default value if they don't exist in json.
public class Person{ [JsonProperty("age", DefaultValueHandling = DefaultValueHandling.Ignore)] // ignore this field in json if it is 0. private int age = 0; }
4). For complex inner field/property, we can define a customized json converter to handle it.
public class Person{ [JsonConverter("job", typeof(JobJsonConverter))] public Job Job { get; set; } } public class Job{ public string Location; public string Description; }
-
Deserialization (from json to object of a specific type)
-
Customized JsonConverter
Even though Newtonsoft.json can also be used to handle complex class, but sometime customized converter is still desired. A convert is a 2-way converting, and it needs to override CanRead & CanWrite to indicate which direction it supports. A convert will inherit JsonConverter
// json --- object public abstract class JsonConverter{ protected JsonConverter(); public virtual bool CanRead { get; } // from json to object public virtual bool CanWrite { get; } // from object to json public abstract bool CanConvert(Type objectType); public abstract object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer); public abstract void WriteJson(JsonWriter writer, object value, JsonSerializer serializer); } // json --- object of a specific type public abstract class JsonConverter<T> : JsonConverter{ // read data from reader, and convert and return a T object public abstract T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer); // convert value to json and write into writer. public abstract void WriteJson(JsonWriter writer, T value, JsonSerializer serializer); }
JsonReader and JsonWriter are abstract classes that handling json I/O. For example, JObject.Load(reader) read the data out and return a JObject object. writer.WriteValue("1") write data.
Convert HttpRequest to a JObject
// HttpResponseMessage response = var content = response.Content; using (var contentStream = await content.ReadAsStreamAsync()) using (var streamReader = new StreamReader(contentStream)) using (var jsonReader = new JsonTextReader(streamReader)) { return JObject.Load(jsonReader); }
-
JObject
JObject