【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.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM