【c#技术】一篇文章搞掂:Newtonsoft.Json Json.Net

一、介绍

Json.Net是一个.Net高性能框架。

特点和好处:

1、为.Net对象和JSON之间的转换提供灵活的Json序列化器;

2、为阅读和书写JSON提供LINQ to JSON;

3、高性能:比.NET内置序列化器更快;

4、可以书写缩进、容易阅读的JSON;

5、支持JSON和XML之间的转换;

6、支持.NET 2, .NET 3.5, .NET 4, .NET 4.5, Silverlight, Windows Phone and Windows 8 Store

JSON 序列化器:当你的JSON和你的.NET类较为接近,需要映射时,建议使用JSON serializer。

LINQ to JSON:当重点在读取JSON数据,或者JSON和.NET类差别较大需要手动映射时,建议使用LINQ to JSON。

二、序列化与反序列化Json

Json.Net提供2种方式进行Json和.Net对象之间的转换

JsonConver

一个比较简单的方法,用于一般场景,提供SerializeObject()和DeserializeObject()方法进行序列化和反序列化。

这是JsonSerialIzer的一个简单的封装。

用法如下:

Product product = new Product();

product.Name = "Apple";
product.ExpiryDate = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };

string output = JsonConvert.SerializeObject(product);
//{
//  "Name": "Apple",
//  "ExpiryDate": "2008-12-28T00:00:00",
//  "Price": 3.99,
//  "Sizes": [
//    "Small",
//    "Medium",
//    "Large"
//  ]
//}

Product deserializedProduct = JsonConvert.DeserializeObject<Product>(output);

 SerializeObject()和DeserializeObject()有一个重载版本,带一个JsonSerializerSettings类型参数,支持使用这个简单方法的时候,仍然可以使用JsonSerializer的一些设置。

JsonSerializer

为了更好地控制这个对象如何转换,可以直接使用JsonSerializer。

JsonSerializer通过JsonTextReader和JsonTextWriter可以直接进行Json和字节流之间的转换。

其它JsonReader和JsonWriter也可以使用,如:

JTokenReader/JTokenWriter用于对象与LINQ to JSON对象之间的转换;

BsonReader/BsonWriter用于对象与BSON之间的转换。

Product product = new Product();
product.ExpiryDate = new DateTime(2008, 12, 28);

JsonSerializer serializer = new JsonSerializer();
serializer.Converters.Add(new JavaScriptDateTimeConverter());
serializer.NullValueHandling = NullValueHandling.Ignore;

using (StreamWriter sw = new StreamWriter(@"c:\json.txt"))
using (JsonWriter writer = new JsonTextWriter(sw))
{
    serializer.Serialize(writer, product);
    // {"ExpiryDate":new Date(1230375600000),"Price":0}
}

JsonSerializer有多个属性,用于自定义如何序列化JSON。这些也可以通过JsonSerializerSettings参数,在JsonConvert上使用。

三、序列化设置Serialization Settings

JsonSerializer有多个属性,用于自定义如何序列化JSON。这些也可以通过JsonSerializerSettings参数,在JsonConvert上使用。

属性的用法:

{//JsonConvert
    string json = "";
    var serializerSettings = new JsonSerializerSettings
    {
        DateFormatHandling = DateFormatHandling.IsoDateFormat,
        ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
        //ContractResolver = new.. .//MassTransit contract resolver that includes private setters
    };
    PageInfo obj = JsonConvert.DeserializeObject<PageInfo>(json, serializerSettings);
}
{//JsonSerializer 
    PageInfo obj = new PageInfo();

    JsonSerializer serializer = new JsonSerializer();
    serializer.DateFormatHandling = DateFormatHandling.IsoDateFormat;

    using (StreamWriter sw = new StreamWriter(@"c:\json.txt"))
    using (JsonWriter writer = new JsonTextWriter(sw))
    {
        serializer.Serialize(writer, obj);
    }
}

以下是各种属性:

DateFormatHandling

控制日期如何序列化。

IsoDateFormat:【默认值】用ISO 8601格式写日期,如:"2012-03-21T05:40Z"

MicrosoftDateFormat:用Microsoft JSON格式写日期,如:"\/Date(1198908717056)\/".

MissingMemberHandling

设置当JSON中包含类中没有的属性时,使用何种处理方式。

Ignore:【默认值】忽略掉该属性。

Error:出现此情况时报错。

ReferenceLoopHandling

设置循环引用的对象,如何进行序列化。

进行判断时,使用的是对象的Object.Equals(Object)方法,你也可以自行重写改对象的Object.Equals(Object) 方法,适应自己的需求。

Error:【默认值】报错。

Ignore:忽略,跳过循环引用对象。

Serialize:强制进行转换。当有循环引用,但并非无限循环时,可以使用。

ReferenceLoopHandling可以作为使用Serializer的一个参数,也可以在对象的属性或集合上使用ItemReferenceLoopHandling来设置。

NullValueHandling

控制空值在序列化和反序列化时如何处理。

NullValueHandling controls how null values on .NET objects are handled during serialization and how null values in JSON are handled during deserialization.

Include:【默认值】写JSON时写空值;赋值对象字段/属性时也给空值。

Ignore:写JSON时,将这个属性跳过;赋值对象字段/属性时也跳过赋值。

可以使用JsonPropertyAttribute特性注解,为单独的字段设置NullValueHandling 

DefaultValueHandling

控制序列化和反序列时如何使用默认值。

Include:【默认值】序列化时,如果对象字段/属性的值等于默认值,会写进JSON;反序列化时,如果JSON值等于默认值,仍会赋值字段/属性的值;

Ignore:在值和默认值相等时,写JSON会跳过该字段/属性;赋值对象,也会跳过该属性。

可以使用JsonPropertyAttribute特性注解,为单独的字段设置DefaultValueHandling。

ObjectCreationHandling

控制反序列化时,如何创建对象和反序列化

Auto:【默认值】给已创建的对象的字段/属性,或集合直接赋值。

Reuse:同Auto。

Replace:赋值前会重新创建对象,再进行赋值和反序列化。

可以使用JsonPropertyAttribute特性注解,为单独的字段设置ObjectCreationHandling。

TypeNameHandling

控制序列化时,在JSON中包含$type属性,表示.NET的类型名;反序列化时,通过$type属性,决定使用什么.NET数据类型。

元数据属性如$type必须在JSON对象的开头。如果无法决定这个顺序,可以通过MetadataPropertyHandling属性移除这个限制。

可以自己实现ISerializationBinder来自定义$type属性和验证

注意:当使用一个来源外部的JSON进行反序列化时,应该小心使用使用TypeNameHandling。当使用非TypeNameHandling.None进行反序列化时时,带入的类型必须使用自定义的ISerializationBinder进行验证。

None:【默认值】不会读或写类型名称。

Objects:除了集合类型,会读和写其它对象类型的名称。

Arrays:会读写集合类型的名称,但其它对象类型不会进行读写。

Auto:Json.NET会自动检测对象/集合是否匹配他定义的类型,如果不匹配,就写类型名称。比如哺乳类动物的类,派生了一个类是狗,当检测到这个类序列化或反序列化时能对应狗这个类,则不需要写类型名;否则才加上这个类型名。

All:所有对象和集合的类型名都写上。

TypeNameHandling可以作为serializer调用是的参数,也可以在对象属性或集合上使用ItemTypeNameHandling。

属性上使用TypeNameHandling,对象或集合使用ItemTypeNameHandling。

TypeNameAssemblyFormat

控制序列化时如何书写类型名

Simple:【默认值】使用类型的部分程序集名称,如System.Data.DataSet。Silverlight and Windows Phone不能使用这种格式。

Full:使用类型的程序集全名,包括version number, culture and public key token。

了解关于FormatterAssemblyStyle的更多信息:https://msdn.microsoft.com/en-us/library/tt9xha1h

SerializationBinder

用于解决序列化和反序列化时,.NET类型和类型名称之间的转换问题。

如果启用TypeNameHandling ,那么必须创建一个自定义ISerializationBinder,来验证带入的类型名称是否安全有效。

MetadataPropertyHandling

设置元数据如$type和id在反序列化时如何读取

为了性能原因,JsonSerializer反序列化时假定元数据都在JSON的开头。如果你无法修改JSON的顺序,可以使用下面属性解除这个限制。

Default:【默认值】仅读取JSON开头的元数据。

ReadAhead:读取JSON任意地方的元数据。

Ignore:忽略元数据。

ConstructorHandling

控制反序列化的时候,初始化对象时,如何使用类的构造器。

Default:【默认值】查找使用的构造器的顺序如下

1、先查找被特性JsonConstructorAttribute标注的构造函数;

2、找public的无参构造函数

3、唯一的public带参构造函数

4、非public无参构造函数

如果到第3步,发现有多个public带参构造函数,则会报错;此时应使用JsonConstructorAttribute标注其中一个构造函数

AllowNonPublicDefaultConstructor:将3,4顺序反转

Converters

序列化和反序列化时,所使用到的JsonConverters的集合

JsonConverter允许手动实现读写,用于特别复杂的JSON或者改变读写方式。

当一个JsonConverter加入后,每一个值序列化或反序列化,都会调用其CanConvert,判断是否需要调用这个JsonConverter。

注意:JsonConverter给予了赋值的完全控制,有些特性像type name and reference handling可能就失效了。

使用方式:

1、JsonConverters可以作为调用serializer的参数;

2、可以在一个对象或属性上使用JsonConverterAttribute;

3、在一个对象的属性或一个集合的子项上使用ItemConverterType

4、a property's object properties or collection items using ItemConverterType【再试搞不懂这句】。

ContractResolver

对每一个.NET类型,JsonSerializer都创建了一个约束如何进行序列化和反序列化,这个约束可以进行自定义。

和上面的区别?暂时未了解。

TraceWriter

Json.NET使用ITraceWriter接口,支持写日志和调试。注册一个TraceWriter在序列化和序列化时进行调试和写日志。

Error

错误,错误时间可以捕获序列化时出现的错误,或者处理该错误后继续序列化,或者让错误抛出到程序中。

四、序列化指引Serialization Guide

Json.NET serializer可以序列化各种各样.NET对象。这个引到关注于它如何运作,首先以较高的视角来了解它,然后再详细了解它的细节。

概要

总体上说Json.NET serializer是这样转换的:

原始.NET值→原始JSON值

.NET数组、集合→JSON数组

其它→JSON对象

如果遇到不正确的JSON,则会报错。

复杂类型

.NET

JSON

IList, IEnumerable, IList<T>, Array

Array (properties on the collection will not be serialized)

IDictionary, IDictionary<TKey, TValue>

Object (dictionary name/values only, properties on the dictionary will not be serialized)

Object (more detail below)

Object

基本类型

.NET

JSON

String

String

Byte

SByte

UInt16

Int16

UInt32

Int32

UInt64

Int64

Integer

Float

Double

Decimal

Float

Enum

Integer (can be the enum value name with StringEnumConverter)

DateTime

String (Serializing Dates in JSON)

Byte[]

String (base 64 encoded)

Type

String (type name)

Guid

String

TypeConverter (convertible to String)

String

序列化类型的分解

Objects:

 (i.e. aren't lists, dictionaries, dynamic, implement ISerializable, etc.)这些.NET类型外的其它类型序列化时都会成为JSON对象。

可以使用JsonObjectAttribute注解,强制一个.NET类型序列化成JSON对象

默认一个类型的属性是使用opt-out模式进行序列化,会把所有公有字段以及有getter的公有属性自动序列化为JSON,除了有JsonIgnoreAttribute标注的字段和属性。可以使用JsonPropertyAttribute序列化私有成员。

可以设置成opt-in模式进行序列化。此时只有添加了JsonPropertyAttribute注解的字段或属性,才会进行序列化。

最后,还可以使用fields模式进行序列化。此时只有不论是公有还是私有的字段会被序列化,属性会被忽略。可以在一个类型上使用JsonObjectAttribute设置MemberSerialization.Fields或使用.NET SerializableAttribute设置IgnoreSerializableAttribute 或DefaultContractResolver为False.

IEnumerable, Lists, and Arrays:

.NET lists (types that inherit from IEnumerable) and .NET arrays are converted to JSON arrays. Because JSON arrays only support a range of values and not properties, any additional properties and fields declared on .NET collections are not serialized. In situations where a type implements IEnumerable but a JSON array is not wanted, then the JsonObjectAttribute can be placed on the type to force it to be serialized as a JSON object instead.
JsonArrayAttribute has options on it to customize the JsonConverter, type name handling, and reference handling that are applied to collection items.
Note that if TypeNameHandling or PreserveReferencesHandling has been enabled for JSON arrays on the serializer, then JSON arrays are wrapped in a containing object. The object will have the type name/reference properties and a $values property, which will have the collection data.
When deserializing, if a member is typed as the interface IList<T>, then it will be deserialized as a List<T>.
You can read more about serializing collections here: Serializing Collections

Dictionaries and Hashtables

.NET dictionaries (types that inherit from IDictionary) are converted to JSON objects. Note that only the dictionary name/values will be written to the JSON object when serializing, and properties on the JSON object will be added to the dictionary's name/values when deserializing. Additional members on the .NET dictionary are ignored during serialization.
When serializing a dictionary, the keys of the dictionary are converted to strings and used as the JSON object property names. The string written for a key can be customized by either overriding ToString() for the key type or by implementing a TypeConverter. A TypeConverter will also support converting a custom string back again when deserializing a dictionary.
JsonDictionaryAttribute has options on it to customize the JsonConverter, type name handling, and reference handling that are applied to collection items.
When deserializing, if a member is typed as the interface IDictionary<TKey, TValue> then it will be deserialized as a Dictionary<TKey, TValue>.
You can read more about serializing collections here: Serializing Collections

Untyped Objects

.NET properties on a class that don't specify a type (i.e. they are just object) are serialized as usual. When untyped properties are deserialized, the serializer has no way of knowing what type to create (unless type name handling is enabled and the JSON contains the type names).
For these untyped properties, the Json.NET serializer will read the JSON into LINQ to JSON objects and set them to the property. JObject will be created for JSON objects; JArray will be created for JSON arrays, and JValue will be created for primitive JSON values.

Dynamic

There are two different usages of dynamic (introduced in .NET 4) in .NET. The first are .NET properties with a type of dynamic. Dynamic properties behave like properties declared as object: any value can be assigned to it, but the difference being that properties and methods can be called on a dynamic property without casting. In Json.NET, dynamic properties are serialized and deserialized exactly the same as untyped objects: because dynamic isn't an actual type, Json.NET falls back to deserializing the JSON as LINQ to JSON objects.
The second usage of dynamic in .NET are by the types that implement IDynamicMetaObjectProvider. This interface lets the implementer create dynamic objects that intercept the property and method calls on an object and use them. ExpandoObject is a good example of a dynamic object.
Dynamic objects are serialized as JSON objects. A property is written for every member name returned by DynamicMetaObject.GetDynamicMemberNames(). A dynamic object's normal properties aren't serialized by default but can be included by placing the JsonPropertyAttribute on them.
When deserializing dynamic objects, the serializer first attempts to set JSON property values on a normal .NET member with the matching name. If no .NET member is found with the property name, then the serializer will call SetMember on the dynamic object. Because there is no type information for dynamic members on a dynamic object, the values assigned to them will be LINQ to JSON objects.

ISerializable

Types that implement ISerializable are serialized as JSON objects. When serializing, only the values returned from ISerializable.GetObjectData are used; members on the type are ignored. When deserializing, the constructor with a SerializationInfo and StreamingContext is called, passing the JSON object's values.
In situations where this behavior is not wanted, the JsonObjectAttribute can be placed on a .NET type that implements ISerializable to force it to be serialized as a normal JSON object.

LINQ to JSON

LINQ to JSON types (e.g. JObject and JArray) are automatically serialized and deserialized to their equivalent JSON when encountered by the Json.NET serializer.

JsonConverter

Serialization of values that are convertible by a JsonConverter (i.e. CanConvert returns true for its type) is completely overridden by the JsonConverter. The test to see whether a value can be converted by the JsonSerializer takes precedence over all other tests.
JsonConverters can be defined and specified in a number of places: in an attribute on a member, in an attribute on a class, and added to the JsonSerializer's converters collection. The priority of which JsonConverter is used is the JsonConverter defined by attribute on a member, then the JsonConverter defined by an attribute on a class, and finally any converters passed to the JsonSerializer.
Note Note
Because a JsonConverter creates a new value, a converter will not work with readonly properties because there is no way to assign the new value to the property. Either change the property to have a public setter or place a JsonPropertyAttribute or DataMemberAttribute on the property.

猜你喜欢

转载自www.cnblogs.com/LiveYourLife/p/10510219.html