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