BsonSerializationException when serializing a Dictionary to BSON

The problem is that the new driver serializes dictionaries as a document by default.

The MongoDB C# driver has 3 ways to serialize a dictionary: Document, ArrayOfArrays & ArrayOfDocuments (more on that in the docs). When it serializes as a document the dictionary keys are the names of the BSON element which has some limitations (for example, as the error suggests, they must be serialized as strings).

In this case, the dictionary’s keys are DateTimes which aren’t serialized as strings, but as Dates so we need to choose another DictionaryRepresentation.

To change the serialization of this specific property we can use the BsonDictionaryOptions attribute with a different DictionaryRepresentation:

[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<DateTime, int> Dictionary { get; private set; }

However, we need to do that on every problematic member individually. To apply this DictionaryRepresentation to all the relevant members we can implement a a new convention:

class DictionaryRepresentationConvention : ConventionBase, IMemberMapConvention
{
    private readonly DictionaryRepresentation _dictionaryRepresentation;
    public DictionaryRepresentationConvention(DictionaryRepresentation dictionaryRepresentation)
    {
        _dictionaryRepresentation = dictionaryRepresentation;
    }
    public void Apply(BsonMemberMap memberMap)
    {
        memberMap.SetSerializer(ConfigureSerializer(memberMap.GetSerializer()));
    }
    private IBsonSerializer ConfigureSerializer(IBsonSerializer serializer)
    {
        var dictionaryRepresentationConfigurable = serializer as IDictionaryRepresentationConfigurable;
        if (dictionaryRepresentationConfigurable != null)
        {
            serializer = dictionaryRepresentationConfigurable.WithDictionaryRepresentation(_dictionaryRepresentation);
        }

        var childSerializerConfigurable = serializer as IChildSerializerConfigurable;
        return childSerializerConfigurable == null
            ? serializer
            : childSerializerConfigurable.WithChildSerializer(ConfigureSerializer(childSerializerConfigurable.ChildSerializer));
    }
} 

Which we register as follows:

ConventionRegistry.Register(
    "DictionaryRepresentationConvention",
    new ConventionPack {new DictionaryRepresentationConvention(DictionaryRepresentation.ArrayOfArrays)},
    _ => true);

Leave a Comment