C# b序列化词典时出现OnSerializationException<;日期时间,T>;拜森
我最近从纽约搬到了纽约 现在,当我序列化一个有字典的类时,有时会遇到以下C# b序列化词典时出现OnSerializationException<;日期时间,T>;拜森,c#,.net,mongodb,mongodb-.net-driver,mongodb-csharp-2.0,C#,.net,Mongodb,Mongodb .net Driver,Mongodb Csharp 2.0,我最近从纽约搬到了纽约 现在,当我序列化一个有字典的类时,有时会遇到以下BsonSerializationException: [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] public Dictionary<DateTime, int> Dictionary { get; private set; } MongoDB.Bson.BsonSerializationException:使用Diction
BsonSerializationException
:
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<DateTime, int> Dictionary { get; private set; }
MongoDB.Bson.BsonSerializationException:使用DictionaryRepresentation时。文档键值必须序列化为字符串
这里有一个简单的例子:
class Hamster
{
public ObjectId Id { get; private set; }
public Dictionary<DateTime,int> Dictionary { get; private set; }
public Hamster()
{
Id = ObjectId.GenerateNewId();
Dictionary = new Dictionary<DateTime, int>();
Dictionary[DateTime.UtcNow] = 0;
}
}
问题是新驱动程序默认情况下将字典序列化为文档 MongoDB C#驱动程序有3种序列化字典的方法:
文档
,阵列法拉利
&阵列文档
()。当它序列化为文档时,字典键是具有某些限制的BSON元素的名称(例如,如错误所示,它们必须序列化为字符串)
在这种情况下,字典的键是DateTime
s,它们没有序列化为字符串,而是序列化为Date
s,因此我们需要选择另一个DictionaryRepresentation
要更改此特定属性的序列化,我们可以将BsonDictionaryOptions
属性与另一个DictionaryRepresentation
一起使用:
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<DateTime, int> Dictionary { get; private set; }
我们登记如下:
ConventionRegistry.Register(
"DictionaryRepresentationConvention",
new ConventionPack {new DictionaryRepresentationConvention(DictionaryRepresentation.ArrayOfArrays)},
_ => true);
上面的答案很好,但不幸的是在某些递归对象层次结构上触发了StackOverflowException——这里是一个稍微改进的最新版本
public class DictionaryRepresentationConvention : ConventionBase, IMemberMapConvention
{
private readonly DictionaryRepresentation _dictionaryRepresentation;
public DictionaryRepresentationConvention(DictionaryRepresentation dictionaryRepresentation = DictionaryRepresentation.ArrayOfDocuments)
{
// see http://mongodb.github.io/mongo-csharp-driver/2.2/reference/bson/mapping/#dictionary-serialization-options
_dictionaryRepresentation = dictionaryRepresentation;
}
public void Apply(BsonMemberMap memberMap)
{
memberMap.SetSerializer(ConfigureSerializer(memberMap.GetSerializer(),Array.Empty<IBsonSerializer>()));
}
private IBsonSerializer ConfigureSerializer(IBsonSerializer serializer, IBsonSerializer[] stack)
{
if (serializer is IDictionaryRepresentationConfigurable dictionaryRepresentationConfigurable)
{
serializer = dictionaryRepresentationConfigurable.WithDictionaryRepresentation(_dictionaryRepresentation);
}
if (serializer is IChildSerializerConfigurable childSerializerConfigurable)
{
if (!stack.Contains(childSerializerConfigurable.ChildSerializer))
{
var newStack = stack.Union(new[] { serializer }).ToArray();
var childConfigured = ConfigureSerializer(childSerializerConfigurable.ChildSerializer, newStack);
return childSerializerConfigurable.WithChildSerializer(childConfigured);
}
}
return serializer;
}
公共类字典表示约定:约定库、IMemberMacConvention
{
私有只读字典表示_DictionaryRepresentation;
公共词典Representation Convention(词典Representation词典Representation=词典Representation.ArrayOfDocuments)
{
//看http://mongodb.github.io/mongo-csharp-driver/2.2/reference/bson/mapping/#dictionary-序列化选项
_dictionaryRepresentation=dictionaryRepresentation;
}
公共无效应用(BsonMemberMap memberMap)
{
SetSerializer(ConfigureSerializer(memberMap.GetSerializer(),Array.Empty());
}
私有IBMOSONSerializer配置序列化程序(IBMOSONSerializer序列化程序,IBMOSONSerializer[]堆栈)
{
if(序列化程序是IDictionaryRepresentationConfigurable字典RepresentationConfigurable)
{
序列化器=dictionaryRepresentation可配置。WithDictionaryRepresentation(\u dictionaryRepresentation);
}
if(序列化程序为IchildSerializerConfiguration ChildSerializerConfiguration)
{
如果(!stack.Contains(ChildSerializerConfiguration.ChildSerializer))
{
var newStack=stack.Union(new[]{serializer}).ToArray();
var childConfigured=ConfigureSerializer(childserializerconfiguration.ChildSerializer,newStack);
返回ChildSerializerConfiguration.WithChildSerializer(childConfigured);
}
}
返回序列化程序;
}
如果像我一样,您只想将此应用于类中的单个字段,我会这样实现(感谢其他答案):
BsonClassMap.RegisterClassMap(cm=>
{
cm.AutoMap();
var memberMap=cm.GetMemberMap(x=>x.DictionaryField);
var serializer=memberMap.GetSerializer();
if(序列化程序是IDictionaryRepresentationConfigurableDictionaryRepresentationSerializer)
序列化器=dictionaryRepresentationSerializer.WithDictionaryRepresentation(DictionaryRepresentation.ArrayOfDocuments);
memberMap.SetSerializer(序列化程序);
});
或作为扩展方法:
BsonClassMap.RegisterClassMap(cm=>
{
cm.AutoMap();
cm.SetDictionaryRepresentation(x=>x.DictionaryField,DictionaryRepresentation.ArrayOfDocuments);
});
公共静态类映射帮助器
{
公共静态BsonClassMap SetDictionaryRepresentation(此BsonClassMap类映射、表达式成员lambda、DictionaryRepresentation表示)
{
var memberMap=classMap.GetMemberMap(memberLambda);
var serializer=memberMap.GetSerializer();
if(序列化程序是IDictionaryRepresentationConfigurableDictionaryRepresentationSerializer)
序列化器=dictionaryRepresentationSerializer.WithDictionaryRepresentation(表示法);
memberMap.SetSerializer(序列化程序);
返回类映射;
}
}
子序列化程序的配置给我带来了一些问题。我检查并注册了一组序列化程序,这导致对子序列化程序进行求值-通常这是延迟求值,但这导致求值比以前更早完成。我没有注册序列化程序这一事实意味着它是延迟求值的注册了一个默认值,然后当我来注册我的时,它告诉我它已经注册了!对于他们来说,这似乎是一个非常糟糕的举动,因为没有要求字典键是字符串,我可以理解的是,这是字符串字典的默认值,其他类型都有其他内容,但假设每个dictionary是一个令人敬畏的字符串
public class DictionaryRepresentationConvention : ConventionBase, IMemberMapConvention
{
private readonly DictionaryRepresentation _dictionaryRepresentation;
public DictionaryRepresentationConvention(DictionaryRepresentation dictionaryRepresentation = DictionaryRepresentation.ArrayOfDocuments)
{
// see http://mongodb.github.io/mongo-csharp-driver/2.2/reference/bson/mapping/#dictionary-serialization-options
_dictionaryRepresentation = dictionaryRepresentation;
}
public void Apply(BsonMemberMap memberMap)
{
memberMap.SetSerializer(ConfigureSerializer(memberMap.GetSerializer(),Array.Empty<IBsonSerializer>()));
}
private IBsonSerializer ConfigureSerializer(IBsonSerializer serializer, IBsonSerializer[] stack)
{
if (serializer is IDictionaryRepresentationConfigurable dictionaryRepresentationConfigurable)
{
serializer = dictionaryRepresentationConfigurable.WithDictionaryRepresentation(_dictionaryRepresentation);
}
if (serializer is IChildSerializerConfigurable childSerializerConfigurable)
{
if (!stack.Contains(childSerializerConfigurable.ChildSerializer))
{
var newStack = stack.Union(new[] { serializer }).ToArray();
var childConfigured = ConfigureSerializer(childSerializerConfigurable.ChildSerializer, newStack);
return childSerializerConfigurable.WithChildSerializer(childConfigured);
}
}
return serializer;
}