.Net深入实战系列—JSON序列化那点事儿
序
当前主流的序列化JSON字符串主要有两种方式:JavaScriptSerializer及Json.net(Nuget标识:Newtonsoft.Json)。JavaScriptSerializer是微软官方提供的一种方法,所以如果你用的是asp.net mvc,在Action中如果你返回的语句写的是”return Json(xxx);“,其实你用的就是JavaScriptSerializer方式。现在更多的人选择的是Json.net,因为它为用户提供了更加清晰地使用体验,清晰在哪?本文主要就是带你走进它们的世界。
JavaScriptSerializer与Json.net
序列化
我们先定义一个测试用的简单类--Person:
1 public class Person
2 {
3 public string Name;
4 public int Age;
5 public Guid TokenId;
6 public DateTime RegTime;
7 public Person Child;
8 public Person Friend;
9 }
类中的成员仅用来区分不同的变量类型。我们分别以JavaScriptSerializer和Json.net来序列化:
1 var person = new Person
2 {
3 Age = 28,
4 Name = "李玉宝<yubaolee:>",//故意添加特殊字符
5 RegTime = DateTime.Now,
6 TokenId = Guid.NewGuid(),
7 Child = new Person
8 {
9 Age = 1,
10 Name = "baby",
11 RegTime = DateTime.Now,
12 TokenId = Guid.NewGuid()
13 }
14 }; //注意这里面的Friend没有赋值,默认为空
15
16 JavaScriptSerializer serializer = new JavaScriptSerializer();
17 var jsstr = serializer.Serialize(person); //使用JavaScriptSerializer序列化
18 string newtonstr = JsonConvert.SerializeObject(person); //使用Json.net序列化
JavaScriptSerializer序列化是先生成一个对象,然后调用它的成员函数Serialize进行序列化;
Json.net直接使用提供的静态成员JsonConvert.SerializeObject进行序列化;
两者使用都比较简单,Json.net调用起来方便那么一丢丢!我们来看一下控制台输出结果:
上面绿色为JavaScriptSerializer的结果,下面黄色背景为Json.net的结果,这里需要注意几个地方:
1、 JavaScriptSerializer序列化后的时间格式:"\/Date(1441813200214)\/" 表示的是1970年1月1日(DateTime的最小值)到date实际表示的日期之差的总毫秒数。通常我们需要把它转成标准的时间格式。可以用下面的方法进行字符串处理:
1 jsstr = Regex.Replace(jsstr, @"\\/Date\((\d+)\)\\/", match =>
2 {
3 DateTime dt = new DateTime(1970, 1, 1);
4 dt = dt.AddMilliseconds(long.Parse(match.Groups[1].Value));
5 dt = dt.ToLocalTime();
6 return dt.ToString("yyyy-MM-dd HH:mm:ss");
7 });
处理完成后的效果:
当然,你还可以通过使用继承JavaScriptConverter的方式,下面反序列化中会具体提及到这种方式。
Json.net默认生成的日期也不方便客户端阅读,需要简单的处理一下:
1 string newtonstr = JsonConvert.SerializeObject(p, Formatting.Indented,
2 new IsoDateTimeConverter() {DateTimeFormat = "yyyy-MM-dd HH:mm:ss"});
2、JavaScriptSerializer序列化会对特殊字符(如<>等)进行编码,比如上面的\u003c \u003e,很多人看到这个的时候,第一感觉就是太扯蛋了,接下来就是各种百度,怎么把这个转成正常的”<>”。实际上你不用做任何操作,这是标准的JS编码方式,前端会自行处理这个问题。比如:
1 <script type="text/javascript">
2 var str = 'yubaolee <yubaolee>'
3 var str2 = 'yubaolee \u003cyubaolee\u003e';
4 alert(str == str2); //结果为true
5 </script>
附:如果你真的不明白\u003c这到底是个什么玩意,请移步:字符编码。
从上面两点可以看出,JavaScriptSerializer序列化出来的JSON字符串容易给人造成一些困惑,而Json.net完全没有上面的两种情况处理。所以现在很多人都在用Json.net,但从Html标准的角度上来看,JavaScriptSerializer序列化出来的结果更符合Html的要求。不过为了操作习惯,还是建议使用Json.net。
反序列化
我们分别用两种方式对上面已经成功序列化的两个字符串进行反序列化:
1 //对JavaScriptSerializer生成的字符串进行反序列化
2 //使用JavaScriptSerializer方式
3 var jsperson = serializer.Deserialize<Person>(jsstr);
4 //使用Json.net方式
5 var newtonperson = JsonConvert.DeserializeObject<Person>(jsstr);
6
7 //对Json.net生成的字符串进行反序列化
8 var jsperson2 = serializer.Deserialize<Person>(newtonstr);
9 var newtonperson2 = JsonConvert.DeserializeObject<Person>(newtonstr);
通过运行会发现4个反序列化代码都能正常运行,而不是像以前某些前辈说的,JavaScriptSerializer序列化的串只能用它反序列化,Json.net序列化的串只能用Json.net来反序列化。
上面反序列化的字符串是程序生成的,能正常反序列化不足为奇。但通常我们要反序列化的字符串是客户提交到服务器上面来的串,他们通常是不完整的,或有些还会出现类型不符的情况。比如:
1 string noChildStr =
2 "{\"Name\":\"李玉宝<yubaolee:>\"," +
3 "\"Age\":28," +
4 "\"RegTime\":\"2015-09-11 00:10:48\"," +
5 "\"Friend\":null}";
6
7 var jsperson = new JavaScriptSerializer().Deserialize<Person>(noChildStr);
8 var newtonperson = JsonConvert.DeserializeObject<Person>(noChildStr);
注意这个字符串中,没有TokenId,没有Child,而且Friend为null。看一看结果:
两个都很智能嘛!解析的结果全部是我们想要的内容。但如果像下面这样呢?
string noChildStr =
"{\"Name\":\"李玉宝<yubaolee:>\"," +
"\"Age\":28," +
"\"RegTime\":\"2015-09-11 00:10:48\"," +
"\"Friend\":null," +
"\"TokenId\":null}"; //注意这个TokenId为空
在运行的时候,程序会直接报错。
错误的内容很容易理解,因为我们把一个null赋值给Guid类型,肯定会出错。在实际的项目操作过程中还有可能出现把一个内容为空的字符串传给Datetime类型,把一个数字传给GUID等各种参数传递的问题,关键是我们还要来处理它们,而不能使程序直接报错崩溃。
1、在JavaScriptSerializer中有一个JavaScriptConverter可以来处理这些问题,它是用来实现JSON序列化中自定义类型的处理。比如下面的代码,就是处理把一个null赋值给Guid的情况:
1 public class PersonJsConverter : JavaScriptConverter
2 {
3 public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
4 {
5 Person person = new Person();
6
7 object value = null;
8 if (dictionary.TryGetValue("TokenId", out value) && value != null)
9 person.TokenId = (Guid) value;
10 //其他字段略...
11
12 return person;
13 }
14
15 public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
16 {
17 Dictionary<string, object> dic = new Dictionary<string, object>();
18 var node = obj as Person;
19 if (node == null)
20 return null;
21 if (!string.IsNullOrEmpty(node.Name))
22 dic.Add("Name", node.Name);
23 //其他字段略...
24 return dic;
25 }
26
27 public override IEnumerable<Type> SupportedTypes
28 {
29 get
30 {
31 return new Type[] { typeof(Person) };
32 }
33 }
34 }
然后在反序列化之前,我们把这个转换注册到实体对象中,这时再执行,程序就一切正常了:
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new PersonJsConverter(), }); var deserialize = serializer.Deserialize<Person>(noChildStr);
2、在使用Json.net时,采用了一种更加优雅的方式来处理这个问题--JsonConverter,它可以单独处理一个指定的类成员变量。这样就不用像上面的JavaScriptConverter一样处理整个类的所有成员。代码如下:
1 public class GuidConverter : JsonConverter
2 {
3 public override bool CanConvert(Type objectType)
4 {
5 return objectType.IsAssignableFrom(typeof(Guid));
6 }
7
8 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
9 {
10 try
11 {
12 return Guid.Parse(reader.Value.ToString());
13 }
14 catch
15 {
16 //如果传进来的值造成异常,则赋值一个初值
17 return Guid.Empty;
18 }
19 }
20
21 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
22 {
23 serializer.Serialize(writer, value);
24 }
25 }
值得注意的是JsonConverter是一个Attribute,所以要在类成员上面添加一个特性:
1 public class Person
2 {
3 public string Name;
4 public int Age;
5 [JsonConverter(typeof(GuidConverter))]
6 public Guid TokenId { get; set; }
7 public DateTime RegTime;
8 public Person Child;
9 public Person Friend;
10 }
这时,再运行程序时,TokenId就会被赋上一个初始的值。看来在反序列化中,Json.net还是更胜一筹。
性能
这是网上给出来两个的性能比较:
综上,在不考虑系统对第三方控件引用的要求情况下,尽量使用Json.net来进行对象序列化处理。
其他常用的序列化方法
说了半天,回顾一下序列化的定义:
序列化:将对象转换成字节流的过程,这样就可以轻松将对象保存在磁盘文件或数据库中。
反序列化:序列化的逆过程,就是将字节流转换回原来的对象的过程。
其他各种格式序列化的方法请参考:
.Net深入实战系列—JSON序列化那点事儿的更多相关文章
- .Net深入实战系列—JSON序列化那点事儿
序 当前主流的序列化JSON字符串主要有两种方式:JavaScriptSerializer及Json.net(Nuget标识:Newtonsoft.Json).JavaScriptSerializer ...
- JSON序列化那点事儿
JSON序列化那点事儿 序 当前主流的序列化JSON字符串主要有两种方式:JavaScriptSerializer及Json.net(Nuget标识:Newtonsoft.Json).JavaScri ...
- SpringBoot基础实战系列(二)springboot解析json与HttpMessageConverter
SpringBoot解析Json格式数据 @ResponseBody 注:该注解表示前端请求后端controller,后端响应请求返回 json 格式数据前端,实质就是将java对象序列化 1.创建C ...
- Newtonsoft.Json C# Json序列化和反序列化工具的使用、类型方法大全 C# 算法题系列(二) 各位相加、整数反转、回文数、罗马数字转整数 C# 算法题系列(一) 两数之和、无重复字符的最长子串 DateTime Tips c#发送邮件,可发送多个附件 MVC图片上传详解
Newtonsoft.Json C# Json序列化和反序列化工具的使用.类型方法大全 Newtonsoft.Json Newtonsoft.Json 是.Net平台操作Json的工具,他的介绍就 ...
- WPF中的常用布局 栈的实现 一个关于素数的神奇性质 C# defualt关键字默认值用法 接口通俗理解 C# Json序列化和反序列化 ASP.NET CORE系列【五】webapi整理以及RESTful风格化
WPF中的常用布局 一 写在开头1.1 写在开头微软是一家伟大的公司.评价一门技术的好坏得看具体的需求,没有哪门技术是面面俱到地好,应该抛弃对微软和微软的技术的偏见. 1.2 本文内容本文主要内容 ...
- 小解系列-自关联对象.Net MVC中 json序列化循环引用问题
自关联对象在实际开发中用的还是比较多,例如常见的树形菜单.本文是自己实际的一个小测试,可以解决循环引用对象的json序列化问题,文笔不好请多见谅,如有错误请指出,希望有更好的解决方案,一起进步. 构造 ...
- SpringBoot系列: Json的序列化和反序列化
============================= 控制 json 序列化/反序列化=============================1. @JsonIgnoreProperties的 ...
- [CXF REST标准实战系列] 一、JAXB xml与javaBean的转换(转)
转自:[CXF REST标准实战系列] 一.JAXB xml与javaBean的转换 文章Points: 1.不认识到犯错,然后得到永久的教训. 2.认识JAXB 3.代码实战 1.不认识到犯错,然后 ...
- Jaskson精讲第7篇-类继承关系下的JSON序列化与反序列化JsonTypeInfo
Jackson是Spring Boot(SpringBoot)默认的JSON数据处理框架,但是其并不依赖于任何的Spring 库.有的小伙伴以为Jackson只能在Spring框架内使用,其实不是的, ...
随机推荐
- JavaWeb——Filter
一.基本概念 之前我们用一篇博文介绍了Servlet相关的知识,有了那篇博文的知识积淀,今天我们学习Filter将会非常轻松,因为Filter有很多地方和Servlet类似,下面在讲Filter的时候 ...
- 拨开迷雾,找回自我:DDD 应对具体业务场景,Domain Model 到底如何设计?
写在前面 除了博文内容之外,和 netfocus 兄的讨论,也可以让你学到很多(至少我是这样),不要错过哦. 阅读目录: 迷雾森林 找回自我 开源地址 后记 毫无疑问,领域驱动设计的核心是领域模型,领 ...
- BIOS中未启用虚拟化支持系列~~例如:因此无法安装Hyper-V
异常处理汇总-服务器系列:http://www.cnblogs.com/dunitian/p/4522983.html 一般都是启动一下CUP虚拟化就可以了 比如华硕的:
- java 利用ManagementFactory获取jvm,os的一些信息--转
原文地址:http://blog.csdn.net/dream_broken/article/details/49759043 想了解下某个Java项目的运行时jvm的情况,可以使用一些监控工具,比如 ...
- 通过AngularJS实现前端与后台的数据对接(一)——预备工作篇
最近,笔者在做一个项目:使用AngularJS,从而实现前端与后台的数据对接.笔者这是第一次做前端与后台的数据对接的工作,因此遇到了许多问题.笔者在这些问题中,总结了一些如何实现前端与后台的数据对接的 ...
- C#通过NPOI操作Excel
参考页面: http://www.yuanjiaocheng.net/webapi/create-crud-api-1-post.html http://www.yuanjiaocheng.net/w ...
- 图解CSS3制作圆环形进度条的实例教程
圆环形进度条制作的基本思想还是画出基本的弧线图形,然后CSS3中我们可以控制其旋转来串联基本图形,制造出部分消失的效果,下面就来带大家学习图解CSS3制作圆环形进度条的实例教程 首先,当有人说你能不能 ...
- css实现文本框和下拉框结合的案例
html 代码部分 <div id="list-name-input" class="list-name-input"> <select ty ...
- Linux实战教学笔记06:Linux系统基础优化
第六节 Linux系统基础优化 标签(空格分隔):Linux实战教学笔记-陈思齐 第1章 基础环境 第2章 使用网易163镜像做yum源 默认国外的yum源速度很慢,所以换成国内的. 第一步:先备份 ...
- Xamarin.Android之使用百度地图起始篇
一.前言 如今跨平台开发层出不穷,而对于.NET而言时下最流行的当然还是Xamarin,不仅仅能够让我们在熟悉的Vs下利用C#开发,在对原生态类库的支持方面也有着非常的好支持,今天我们将会以百度地图类 ...