问题
I am simply trying to serialize and deserialize a string array in Bson format using Json.NET, but the following code fails:
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, typeof(string[]));
bytes = ms.ToArray();
}
// Deserialization
using (var ms = new MemoryStream(bytes))
using (var bson = new BsonReader(ms))
{
// Exception here
array = jsonSerializer.Deserialize<string[]>(bson);
}
Exception message:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.String[]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
How can I get this to work?
回答1:
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.
回答2:
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:
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(); }
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.
回答3:
In general, you could check data type first before set ReadRootValueAsArray to true, like this:
if (typeof(IEnumerable).IsAssignableFrom(type))
bSonReader.ReadRootValueAsArray = true;
回答4:
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.
来源:https://stackoverflow.com/questions/16910369/bson-array-deserialization-with-json-net