【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(, , );
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(, , ); 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.
【c#技术】一篇文章搞掂:Newtonsoft.Json Json.Net的更多相关文章
- 【进阶技术】一篇文章搞掂:Spring Cloud Stream
本文总结自官方文档http://cloud.spring.io/spring-cloud-static/spring-cloud-stream/2.1.0.RC3/single/spring-clou ...
- 【已转移】【Java架构:基础技术】一篇文章搞掂:Spring
本文篇幅较长,建议合理利用右上角目录进行查看(如果没有目录请刷新). 本文是对<SPRING实战第4版>的总结,大家也可以去仔细研读该书 [------------------------ ...
- 【进阶技术】一篇文章搞掂:OAuth2
一.第一步 1.什么是OAuth2,为什么应该了解 应用程序请求资源所有者进行认证,并接受tokens来访问这些资源应用程序不是以控制资源的“人”的角度去访问资源,而是用许可证举例,备用钥匙,车主主钥 ...
- 【Java架构:基础技术】一篇文章搞掂:Spring Boot
本文篇幅较长,建议合理利用右上角目录进行查看(如果没有目录请刷新). 本文是对<Spring Boot 实战第4版>的总结,大家也可以去仔细研读该书 注意,书中使用的Spring Boot ...
- 【进阶技术】一篇文章搞掂:Docker
注意!!注意系统内存,一开始我使用阿里云1核1G系统,各种问题,搞了几天,原来是内存不足 一.使用VM虚拟机,安装CentOS7.X系统,并安装和使用Docker 1.1.虚拟机安装CentOS7.X ...
- 【Java架构:进阶技术】——一篇文章搞掂:JVM调优
Sun官方定义的Java技术体系: Java程序设计语言 各种硬件平台上的Java虚拟机 Class文件格式 Java API类库 来自商业机构和开源社区的第三方Java类库 JDK(Java Dev ...
- 【进阶技术】一篇文章搞掂:Spring高级编程
本文篇幅较长,建议合理利用右上角目录进行查看(如果没有目录请刷新). 本文基于<Spring5高级编程>一书进行总结和扩展,大家也可以自行研读此书. 十一.任务调度 任务调度主要由三部分组 ...
- 【Java架构:基础技术】一篇文章搞掂:Spring Boot 官方文档解读
本文篇幅较长,建议合理利用右上角目录进行查看(如果没有目录请刷新). 本文内容大部分是翻译和总结官方文档,可以到https://docs.spring.io/spring-boot/docs查看(此地 ...
- 【已转移】【Java架构:基础技术】一篇文章搞掂:Java 8
本文篇幅较长,建议合理利用右上角目录进行查看(如果没有目录请刷新). 一.Java的历史与演变 目的:为完全了解Java,需要理解Java的诞生原因.成型动力以及他继承的思想. 计算机语言的创新与发展 ...
随机推荐
- hdu2182Frog(动态规划)
Problem Description A little frog named Fog is on his way home. The path's length is N (1 <= N &l ...
- Songwriter CF1252-E(贪心)
题意: 已知一个序列a,问能否将a映射到序列b,使得相邻元素之间的大小关系不变(三种),且相邻元素不能相差超过k,且每个元素范围在[L,R]内.如果能,求字典序最小的b. 思路: 可以设b[1]的范围 ...
- 结合Pool进程池进程,实现进程之间的通讯,稍微复杂的运用
#进程池中的Queue """ 如果要用Pool创建进程,就需要multiprocessing.Manager()中的Queue() 而不是multiprocessing ...
- MySQL数据库忘记密码如何重新设置?
前 言当我们忘记了MySQL数据库密码后,该如何重新进行设置? 操作步骤步骤1:cmd打开命名窗口 步骤2:关闭正在运行的MySQL服务(命令:net stop mysql)(如果:此时MySQL正在 ...
- [Linux] 003 分区
1. 磁盘分区 使用分区编辑器再磁盘上划分几个逻辑部分 不用类的目录与文件可以存储进不同的分区 2. 分区类型 主分区 最多只能有 4 个 扩展分区 最多只能有 1 个 主分区加扩展分区最多为 4 个 ...
- Spring Boot静态资源
1.4 SpringBoot静态资源 1.4.1 默认静态资源映射 Spring Boot 对静态资源映射提供了默认配置 Spring Boot 默认将 /** 所有访问映射到以下目录: classp ...
- elasticsearch 深入 —— Post Filter后置过滤器
过滤查询以及聚合 A natural extension to aggregation scoping is filtering. Because the aggregation operates i ...
- 一、简单的移动端tab头部二级下拉导航栏,向下弹出,向上隐藏
一.简单的移动端tab头部二级下拉导航栏,向下弹出,向上隐藏 <html lang="en"> <head> <meta charset=" ...
- git提交代码冲突解决
1.git stash save "说明信息" 2.git stash lish 3.git pull 4.git stash pop stash@{编号}
- nuxtJs - axios 的 IE 兼容性的问题
因为考虑SEO, 所以采用nuxt.js进行服务端渲染, 用熟了vue, nuxt无缝对接简直不要太爽 烦人的需求又来了, 要兼容IE ~~ 兼容处理 无非就是babel 将高级语法转成弱智IE看得懂 ...