Bson array (de)serialization with Json.NET

ぃ、小莉子 提交于 2019-12-01 16:19:32

Set ReadRootValueAsArray to true on BsonReader

http://james.newtonking.com/projects/json/help/index.html?topic=html/P_Newtonsoft_Json_Bson_BsonReader_ReadRootValueAsArray.htm

This setting is required because the BSON data spec doesn't save metadata about whether the root value is an object or an array.

Hmmm, from where I sit, your code should work, but Json.Net seems to think that your serialized array of strings is a dictionary. This could be because, according to the BSON specification, arrays actually do get serialized as a list of key-value pairs just like objects do. The keys in this case are simply the string representations of the array index values.

In any case, I was able to work around the issue in a couple of different ways:

  1. Deserialize to a Dictionary and then manually convert it back to an array.

    var jsonSerializer = new JsonSerializer();
    var array = new string[] { "A", "B" };
    
    // Serialization
    byte[] bytes;
    using (var ms = new MemoryStream())
    using (var bson = new BsonWriter(ms))
    {
        jsonSerializer.Serialize(bson, array);
        bytes = ms.ToArray();
    }
    
    // Deserialization
    using (var ms = new MemoryStream(bytes))
    using (var bson = new BsonReader(ms))
    {
        var dict = jsonSerializer.Deserialize<Dictionary<string, string>>(bson);
        array = dict.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToArray();
    }
    
  2. Wrap the array in an outer object.

    class Wrapper
    {
        public string[] Array { get; set; }
    }
    

    Then serialize and deserialize using the wrapper object.

    var jsonSerializer = new JsonSerializer();
    var obj = new Wrapper { Array = new string[] { "A", "B" } };
    
    // Serialization
    byte[] bytes;
    using (var ms = new MemoryStream())
    using (var bson = new BsonWriter(ms))
    {
        jsonSerializer.Serialize(bson, obj);
        bytes = ms.ToArray();
    }
    
    // Deserialization
    using (var ms = new MemoryStream(bytes))
    using (var bson = new BsonReader(ms))
    {
        obj = jsonSerializer.Deserialize<Wrapper>(bson);
    }
    

Hope this helps.

In general, you could check data type first before set ReadRootValueAsArray to true, like this:

if (typeof(IEnumerable).IsAssignableFrom(type)) 
    bSonReader.ReadRootValueAsArray = true;

I know this is an old thread but I discovered a easy deserialization while using the power of MongoDB.Driver

You can use BsonDocument.parse(JSONString) to deserialize a JSON object so to deserialize a string array use this:

string Jsonarray = "[\"value1\", \"value2\", \"value3\"]";
BsonArray deserializedArray = BsonDocument.parse("{\"arr\":" + Jsonarray + "}")["arr"].asBsonArray;

deserializedArray can then be used as any array such as a foreach loop.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!