C#中Bson与Json的序列化与反序列化


参考文章:

1.http://blog.csdn.net/z69183787/article/details/26709505

2.https://blog.csdn.net/dai815904261/article/details/78919414

3.https://www.cnblogs.com/fengxuehuanlin/p/5700282.html

4.https://www.cnblogs.com/yanweidie/p/4605212.html

一、Bson和 Json的区别

  BSON是由10gen开发的一个数据格式,是一种基于 JSON 的二进制序列化格式,用于 MongoDB 存储文档并进行远程过程调用。BSON基于JSON格式,选择JSON进行改造的原因主要是JSON的通用性及JSON的schemaless的特性。


BSON主要会实现以下三点目标:
(1)更快的遍历速度
  对JSON格式来说,太大的JSON结构会导致数据遍历非常慢。在JSON中,要跳过一个文档进行数据读取,需要对此文档进行扫描才行,需要进行麻烦的数据结构匹配,比如括号的匹配,而BSON对JSON的一大改进就是,它会将JSON的每一个元素的长度存在元素的头部,这样你只需要读取到元素长度就能直接seek到指定的点上进行读取了。
(2)操作更简易
  对JSON来说,数据存储是无类型的,比如你要修改基本一个值,从9到10,由于从一个字符变成了两个,所以可能其后面的所有内容都需要往后移一位才可以。而使用BSON,你可以指定这个列为数字列,那么无论数字从9长到10还是100,我们都只是在存储数字的那一位上进行修改,不会导致数据总长变大。当然,在MongoDB中,如果数字从整形增大到长整型,还是会导致数据总长变大的。
(3)增加了额外的数据类型
  JSON是一个很方便的数据交换格式,但是其类型比较有限。BSON在其基础上增加了“byte array”数据类型。这使得二进制的存储不再需要先base64转换后再存成JSON。大大减少了计算开销和数据大小。
但是,在有的时候,BSON相对JSON来说也并没有空间上的优势,比如对{“field”:7},在JSON的存储上7只使用了一个字节,而如果用BSON,那就是至少4个字节(32位)
目前在10gen的努力下,BSON已经有了针对多种语言的编码解码包。并且都是Apache 2 license下开源的。并且还在随着MongoDB进一步地发展。

 

BSON 支持的数据类型如表所示。

BSON 支持的数据类型
类型 描述示例
NULL 表示空值或者不存在的字段,{"x" : null}
Boolean 布尔型有 true 和 false,{"x" : true}
Number 数值:客户端默认使用 64 位浮点型数值。{"x" : 3.14} 或 {"x" : 3}。对于整型值,包括 NumberInt(4 字节符号整数)或 NumberLong(8 字节符号整数),用户可以指定数值类型,{"x" : NumberInt("3")}
String 字符串:BSON 字符串是 UTF-8,{"x" : "中文"}
Regular Expression 正则表达式:语法与 JavaScript 的正则表达式相同,{"x" : /[cba]/}
Array 数组:使用“[]”表示,{"x" : ["a", "b", "c"]}
Object 内嵌文档:文档的值是嵌套文档,{"a" : {"b" : 3}}
ObjectId 对象 id:对象 id 是一个 12 字节的字符串,是文档的唯一标识,{"x" : objectId()}
BinaryData 二进制数据:二进制数据是一个任意字节的字符串。它不能直接在 Shell 中使用。如果要将非 UTF-8 字符保存到数据库中,二进制数据是唯一的方式
JavaScript 代码:查询和文档中可以包括任何 JavaScript 代码,{"x" : function(){/*...*/}}
Data 日期:{"x" : new Date()}
Timestamp 时间戳:var a = new Timestamp()


二、Json的序列化和反序列化

1.使用JavaScriptSerializer类:

//使用JavaScriptSerializer方式需要引入的命名空间,这个在程序集System.Web.Extensions.dll.中

using System.Web.Script.Serialization;

 

2.使用DataContractJsonSerializer类:

 //实体中的特性[DataMember],[DataContract],是使用DataContractJsonSerializer序列化和反序列化必须要加的

//使用DataContractJsonSerializer方式需要引入的命名空间,在System.Runtime.Serialization.dll.中

using System.Runtime.Serialization.Json;

 

3.(推荐)使用Json.Net(即Newtonsoft.Json)类库:

using Newtonsoft.Json;

反序列化:JsonConvert.DeserializeObject()

序列化:JsonConvert.SerializeObject()

Json.Net是支持序列化和反序列化DataTable,DataSet,Entity Framework和Entity的。序列化和反序列化常用到JsonSerializerSettings类进行设置

 1 class Program  2 {  3 static void Main(string[] args)  4 {  5     //序列化操作
 6     var json = new { user = new { name = "fxhl", age = 23 }};  7     string jsonData = JsonConvert.SerializeObject(json);  8  Console.WriteLine(jsonData);  9     //反序列化操作方法一
10     Person p1= JsonConvert.DeserializeObject<Person>(jsonData); 11  Console.WriteLine(p1.user.name); 12     //反序列化操作方法二
13     string json2 = "[{\"user\":{\"name\":\"fxhl\",\"age\":23}}]"; 14     List<Person> listp2= JsonConvert.DeserializeObject<List<Person>>(json2); 15     Console.WriteLine(listp2[0].user.name); 16  Console.ReadKey(); 17 } 18 } 19 public class Person 20 { 21     public Person user { get; set; } 22     public string name { get; set; } 23     public int age { get; set; } 24 }

 

三、Bson的序列化与反序列化

反序列化:BsonSerializer.Deserialize()

序列化:BsonExtensionMethods.ToJson()

 

四、高级用法

请点原文链接查看Newtonsoft.Json高级用法

 

1.使用特性实现特殊化处理

  序列化和反序列化对象时,可以通过在字段和类上添加特性,实现特殊化处理

 

1.1 类特性

  [BsonIgnoreExtraElements]:BsonSerializer时,忽略未匹配到i的字段,可避免在反序列化时会因为缺少_id字段而无法成功反序列化对象。

  [JsonObject(MemberSerialization.OptIn)]

OptOut 默认值,类中所有公有成员会被序列化,如果不想被序列化,可以用特性JsonIgnore
OptIn 默认情况下,所有的成员不会被序列化,类中的成员只有标有特性JsonProperty的才会被序列化,当类的成员很多,但客户端仅仅需要一部分数据时,很有用

 

 

 

1.2字段特性

  可以设置字段是否被忽略、默认值、null值处理和类型等等处理。下面仅列出一些常用特性:

1、[Newtonsoft.Json.JsonIgnore]特性:使用Newtonsoft.Json序列化时字段不会被序列化。

2、[System.Web.Script.Serialization.ScriptIgnore]特性:使用JavaScriptSerializer序列化时字段不会被序列化。

3、[System.Xml.Serialization.XmlIgnore]特性:字段不会被序列化成XML。

4、[BsonIgnore]特性:BsonSerializer时,字段不会被序列化。

5、[BsonElement]:自定义字段关联的名称和特殊处理
6、[JsonProperty]:自定义字段关联的名称和特殊处理

7、[BsonRepresentation]

 

2.采用JsonSerialzerSettings统一设置

  JsonSerialzerSettings是JsonConvert方法中的参数,当所有字段做相同处理时,可直接配置在JsonSerialzerSettings中。

  例如,json序列化时,如果时间类型中的毫秒是0,则在序列化时会被省略,

//设置不忽略时间的毫秒。
JsonSerializerSettings settings = new JsonSerializerSettings(); IsoDateTimeConverter dateConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fff'Z'" }; settings.Converters.Add(dateConverter); string jsonStr = JsonConvert.SerializeObject(arr, settings); //反序列化设置 忽略不可匹配的项
var jSetting = new JsonSerializerSettings(); jSetting.NullValueHandling = NullValueHandling.Ignore; string devicejsonstr = FileHelper.GetContentFromFile(devicePath); device = JsonConvert.DeserializeObject<List<Device>>(devicejsonstr, jSetting);

 

3.JsonWriterSettings配置

  把一个对象用BsonExtensionMethods.ToJson()方法得到的不是标准Json格式的字符串。本文开头的表格中列出了Bson支持Value的类型。

 

  默认输出是Shell模式:整型是NumberLong(),Id是ObjectId(),DateTime是 ISODate("2019-12-23T07:41:09.397Z")。Strict模式: "_id" : { "$oid" : "5e0073335b0fd0502cb9ddef" }, "Date" : { "$date" : 1577087795171 }。可以使用如下方法改变Bson对象序列化时的输出格式:

 

      public class Test
        {
            public ObjectId Id { get; set; }
            public DateTime CreateDate { get; set; }
            public BsonDocument Data { get; set; }
        }

var jsonWriterSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };

string bsonStr = bsonObj.ToJson(jsonWriterSettings);

 

  不同序列化方式结果输出如下:

 

bson-Shell模式:{ "_id" : ObjectId("5e0075c4b2cde92970d12a47"), "CreateDate" : ISODate("2019-12-23T08:07:32.283Z"), "Data" : { "id" : 11 } }
bson-Strict模式:{ "_id" : { "$oid" : "5e0075c4b2cde92970d12a47" }, "CreateDate" : { "$date" : 1577088452283 }, "Data" : { "id" : 11 } }
json无配置:{"Id":"5e0075c4b2cde92970d12a47","CreateDate":"2019-12-23T16:07:32.2836112+08:00","Data":[{"Name":"id","Value":11}]}

  可以明显看出这三种类型的输出都不符合Json标准格式,用Json反序列化Bson的结果或异常!

4.Bson序列化Dictionary

  MongoDB C#驱动程序有三种序列化字典的方法:Document,ArrayOfArrays& ArrayOfDocuments(more on that in the docs)。默认是将字典序列化为文档(Document),当它作为文档序列化时,字典键是具有一些限制的BSON元素的名称(例如,dictionary的key必须被串行化为字符串)

要更改此特定属性的序列化,我们可以使用不同的DictionaryRepresentation的BsonDictionaryOptions属性:

[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<DateTime, int> Dictionary { get; private set; }

但是,我们需要对每一个有问题的成员单独做到这一点.要将此DictionaryRepresentation应用于所有相关成员,我们可以实现一个新的约定:

 1 class DictionaryRepresentationConvention : ConventionBase, IMemberMapConvention
 2 {
 3     private readonly DictionaryRepresentation _dictionaryRepresentation;
 4     public DictionaryRepresentationConvention(DictionaryRepresentation dictionaryRepresentation)
 5     {
 6         _dictionaryRepresentation = dictionaryRepresentation;
 7     }
 8     public void Apply(BsonMemberMap memberMap)
 9     {
10         memberMap.SetSerializer(ConfigureSerializer(memberMap.GetSerializer()));
11     }
12     private IBsonSerializer ConfigureSerializer(IBsonSerializer serializer)
13     {
14         var dictionaryRepresentationConfigurable = serializer as IDictionaryRepresentationConfigurable;
15         if (dictionaryRepresentationConfigurable != null)
16         {
17             serializer = dictionaryRepresentationConfigurable.WithDictionaryRepresentation(_dictionaryRepresentation);
18         }
19 
20         var childSerializerConfigurable = serializer as IChildSerializerConfigurable;
21         return childSerializerConfigurable == null
22             ? serializer
23             : childSerializerConfigurable.WithChildSerializer(ConfigureSerializer(childSerializerConfigurable.ChildSerializer));
24     }
25 }

我们注册如下:

 

ConventionRegistry.Register(
    "DictionaryRepresentationConvention",
    new ConventionPack {new DictionaryRepresentationConvention(DictionaryRepresentation.ArrayOfArrays)},
    _ => true);

五、注意事项

1.Bson可以看作是Json的特异化,有相同点,也有很大的区别。所以再做序列化和反序列化时,代码里最好一直用同一套,或者是用bson和json有严格的隔离,不要用着bson序列化,再用Json反序列化。

2.代码内部转换时,推荐使用Bson进行序列化和反序列化。因为如果类中存在BsonDocument类型的字段,Json会反序列化失败!!

3.前后端交互时,推荐使用Json进行序列化和反序列化。由于前端一般用标准Json格式,用Bson的话要自己写序列化接口

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM