从 BsonDocument 反序列化为字符串并序列化回 BsonDocument
Deserializing from BsonDocument to string and serializing back to BsonDocument
我有一个要求,我需要一个 属性,它实际上是 MongoDB 集合中的一个 JSON 值,需要将其反序列化为一个字符串。此转换引发 "Cannot deserialize a 'String' from a BsonType 'Document'" 异常。
我尝试实现一个 JSON 自定义转换器,但由于该值被视为 BsonDocument,所以它没有帮助,而且我遇到了同样的异常。我还需要它的原始格式,因为我需要将它转换回 BsonDocument 中。我想我需要一个自定义的 Bson serializer/deserializer。
来自 MongoDB 集合的传入示例文档:
{
"name": "Jane Doe",
"dob": {
"month": "Sep",
"day": 09,
"year": 1987
}
}
反序列化所需的类型:
public class Person
{
public string name { get; set; }
public Dob dob { get; set; }
public class Dob
{
public string month { get; set; }
public int day { get; set; }
public int year { get; set; }
}
}
我希望它反序列化为的类型:
public class Person
{
public string name { get; set; }
public string dob { get; set; }
}
总而言之,您的模型上有一个面向 public 的 string
属性,其中包含 JSON,您希望将其内部序列化为 MongoDB 通过将 JSON 字符串反序列化为某个中间 DTO,然后将 DTO 本身序列化为 Mongo.
这里有几种方法可以解决您的问题。
首先,你可以在你的数据模型中引入一个私有 DTO 值 属性 Dob SerializedDOB { get; set; }
,用 [= 标记 属性 26=] 强制对其进行序列化,然后将 dob
修改为非序列化代理项 属性,在其 getter 和 setter。以下代码展示了这种方法:
public class Person
{
public string name { get; set; }
[BsonIgnore]
public string dob
{
get => BsonExtensionMethods.ToJson(SerializedDOB);
set => SerializedDOB = MyBsonExtensionMethods.FromJson<Dob>(value);
}
[BsonElement("dob")]
Dob SerializedDOB { get; set; }
class Dob // The DTO
{
public string month { get; set; }
public int day { get; set; }
public int year { get; set; }
}
}
这种方法的优点是,通过使 JSON 字符串成为代理项,setter 自动确保其格式正确。
演示 fiddle #1 here.
其次,您可以为 dob
创建一个自定义 SerializerBase<string>
,在 (反序列化。以下代码展示了这种方法:
public class Person
{
public string name { get; set; }
[BsonSerializer(typeof(JsonStringAsObjectSerializer<Dob>))]
public string dob { get; set; }
class Dob // The DTO
{
public string month { get; set; }
public int day { get; set; }
public int year { get; set; }
}
}
public class JsonStringAsObjectSerializer<TObject> : SerializerBase<string> where TObject : class
{
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, string value)
{
if (value == null)
{
var bsonWriter = context.Writer;
bsonWriter.WriteNull();
}
else
{
var obj = MyBsonExtensionMethods.FromJson<TObject>(value);
var serializer = BsonSerializer.LookupSerializer(typeof(TObject));
serializer.Serialize(context, obj);
}
}
public override string Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonReader = context.Reader;
var serializer = BsonSerializer.LookupSerializer(typeof(TObject));
var obj = (TObject)serializer.Deserialize(context);
return (obj == null ? null : BsonExtensionMethods.ToJson(obj));
}
}
这种方法的优点是 JsonStringAsObjectSerializer<TObject>
可以在出现此需求时重复使用。
演示 fiddle #2 here.
以下扩展方法与两种解决方案一起使用,将 JSON 字符串反序列化为指定类型,因为令人困惑的是,BsonExtensionMethods
has a ToJson()
方法没有 FromJson()
方法:
public static partial class MyBsonExtensionMethods
{
// Not sure why but BsonExtensionMethods.cs seems to lack methods for deserializing from JSON, so I added some here.
// See https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Bson/BsonExtensionMethods.cs
public static TNominalType FromJson<TNominalType>(
string json,
JsonReaderSettings readerSettings = null,
IBsonSerializer<TNominalType> serializer = null,
Action<BsonDeserializationContext.Builder> configurator = null)
{
return (TNominalType)FromJson(json, typeof(TNominalType), readerSettings, serializer, configurator);
}
public static object FromJson(
string json,
Type nominalType,
JsonReaderSettings readerSettings = null,
IBsonSerializer serializer = null,
Action<BsonDeserializationContext.Builder> configurator = null)
{
if (nominalType == null || json == null)
throw new ArgumentNullException();
serializer = serializer ?? BsonSerializer.LookupSerializer(nominalType);
if (serializer.ValueType != nominalType)
throw new ArgumentException(string.Format("serializer.ValueType {0} != nominalType {1}.", serializer.GetType().FullName, nominalType.FullName), "serializer");
using (var textReader = new StringReader(json))
using (var reader = new JsonReader(textReader, readerSettings ?? JsonReaderSettings.Defaults))
{
var context = BsonDeserializationContext.CreateRoot(reader, configurator);
return serializer.Deserialize(context);
}
}
}
我有一个要求,我需要一个 属性,它实际上是 MongoDB 集合中的一个 JSON 值,需要将其反序列化为一个字符串。此转换引发 "Cannot deserialize a 'String' from a BsonType 'Document'" 异常。
我尝试实现一个 JSON 自定义转换器,但由于该值被视为 BsonDocument,所以它没有帮助,而且我遇到了同样的异常。我还需要它的原始格式,因为我需要将它转换回 BsonDocument 中。我想我需要一个自定义的 Bson serializer/deserializer。
来自 MongoDB 集合的传入示例文档:
{
"name": "Jane Doe",
"dob": {
"month": "Sep",
"day": 09,
"year": 1987
}
}
反序列化所需的类型:
public class Person
{
public string name { get; set; }
public Dob dob { get; set; }
public class Dob
{
public string month { get; set; }
public int day { get; set; }
public int year { get; set; }
}
}
我希望它反序列化为的类型:
public class Person
{
public string name { get; set; }
public string dob { get; set; }
}
总而言之,您的模型上有一个面向 public 的 string
属性,其中包含 JSON,您希望将其内部序列化为 MongoDB 通过将 JSON 字符串反序列化为某个中间 DTO,然后将 DTO 本身序列化为 Mongo.
这里有几种方法可以解决您的问题。
首先,你可以在你的数据模型中引入一个私有 DTO 值 属性 Dob SerializedDOB { get; set; }
,用 [= 标记 属性 26=] 强制对其进行序列化,然后将 dob
修改为非序列化代理项 属性,在其 getter 和 setter。以下代码展示了这种方法:
public class Person
{
public string name { get; set; }
[BsonIgnore]
public string dob
{
get => BsonExtensionMethods.ToJson(SerializedDOB);
set => SerializedDOB = MyBsonExtensionMethods.FromJson<Dob>(value);
}
[BsonElement("dob")]
Dob SerializedDOB { get; set; }
class Dob // The DTO
{
public string month { get; set; }
public int day { get; set; }
public int year { get; set; }
}
}
这种方法的优点是,通过使 JSON 字符串成为代理项,setter 自动确保其格式正确。
演示 fiddle #1 here.
其次,您可以为 dob
创建一个自定义 SerializerBase<string>
,在 (反序列化。以下代码展示了这种方法:
public class Person
{
public string name { get; set; }
[BsonSerializer(typeof(JsonStringAsObjectSerializer<Dob>))]
public string dob { get; set; }
class Dob // The DTO
{
public string month { get; set; }
public int day { get; set; }
public int year { get; set; }
}
}
public class JsonStringAsObjectSerializer<TObject> : SerializerBase<string> where TObject : class
{
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, string value)
{
if (value == null)
{
var bsonWriter = context.Writer;
bsonWriter.WriteNull();
}
else
{
var obj = MyBsonExtensionMethods.FromJson<TObject>(value);
var serializer = BsonSerializer.LookupSerializer(typeof(TObject));
serializer.Serialize(context, obj);
}
}
public override string Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonReader = context.Reader;
var serializer = BsonSerializer.LookupSerializer(typeof(TObject));
var obj = (TObject)serializer.Deserialize(context);
return (obj == null ? null : BsonExtensionMethods.ToJson(obj));
}
}
这种方法的优点是 JsonStringAsObjectSerializer<TObject>
可以在出现此需求时重复使用。
演示 fiddle #2 here.
以下扩展方法与两种解决方案一起使用,将 JSON 字符串反序列化为指定类型,因为令人困惑的是,BsonExtensionMethods
has a ToJson()
方法没有 FromJson()
方法:
public static partial class MyBsonExtensionMethods
{
// Not sure why but BsonExtensionMethods.cs seems to lack methods for deserializing from JSON, so I added some here.
// See https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Bson/BsonExtensionMethods.cs
public static TNominalType FromJson<TNominalType>(
string json,
JsonReaderSettings readerSettings = null,
IBsonSerializer<TNominalType> serializer = null,
Action<BsonDeserializationContext.Builder> configurator = null)
{
return (TNominalType)FromJson(json, typeof(TNominalType), readerSettings, serializer, configurator);
}
public static object FromJson(
string json,
Type nominalType,
JsonReaderSettings readerSettings = null,
IBsonSerializer serializer = null,
Action<BsonDeserializationContext.Builder> configurator = null)
{
if (nominalType == null || json == null)
throw new ArgumentNullException();
serializer = serializer ?? BsonSerializer.LookupSerializer(nominalType);
if (serializer.ValueType != nominalType)
throw new ArgumentException(string.Format("serializer.ValueType {0} != nominalType {1}.", serializer.GetType().FullName, nominalType.FullName), "serializer");
using (var textReader = new StringReader(json))
using (var reader = new JsonReader(textReader, readerSettings ?? JsonReaderSettings.Defaults))
{
var context = BsonDeserializationContext.CreateRoot(reader, configurator);
return serializer.Deserialize(context);
}
}
}