[CSHARP-1166] Serialization of dictionary of dictionaries always fails Created: 20/Jan/15  Updated: 05/Apr/19  Resolved: 27/Jan/16

Status: Closed
Project: C# Driver
Component/s: BSON, Serialization
Affects Version/s: 2.0
Fix Version/s: None

Type: Task Priority: Major - P3
Reporter: Bar Arnon Assignee: Unassigned
Resolution: Done Votes: 0
Labels: driver, question
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
is related to CSHARP-938 Write API Documentation and Review Vi... Closed

 Description   

When you serialize a dictionary with DictionaryRepresentation.Document the keys must be serialized as strings.

If you have a dictionary with different keys you can use the BsonDictionaryOptionsAttribute to change the DictionaryRepresentation. However in a dictionary of dictionaries, you can't affect the inner dictionaries so the following class can never be serialized:

    public class Hamster
    {
        public ObjectId Id { get; private set; }
        public Dictionary<string, Dictionary<DateTime,string>> Dictionary { get; private set; }
        public Hamster()
        {
            Id = ObjectId.GenerateNewId();
            Dictionary = new Dictionary<string, Dictionary<DateTime, string>>();
            Dictionary["hamster"] = new Dictionary<DateTime, string> {{DateTime.UtcNow, "hamster"}};
        }
    }

I believe the issue is in BsonDictionaryOptionsAttribute.Apply where the DictionaryRepresentation is applied to the serializer or the child serializer (via base.Apply(serializer)) instead of to both (if it applies).

The same is true for list of dictionaries and probably other collections.



 Comments   
Comment by Craig Wilson [ 27/Jan/16 ]

Hi Bar,

I'm going to close this as works as designed. I'm not sure that the flattened attributes provide a good way to handle this type of scenario. Your convention solution is a great way to handle this.

Craig

Comment by Bar Arnon [ 20/Jan/15 ]

So, looking at this answer I managed to create a convention that solves this issue:

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));
    }
} 

Comment by Bar Arnon [ 20/Jan/15 ]

When I mentioned list I meant that serializing a List<Dictionary<DateTime,string>> would throw an exception but it can be fixed by adding the appropriate BsonDictionaryOptionsAttribute since it doesn't apply to list but it does to the inner serializer. In Dictionary<string,Dictionary<DateTime,string>> it can't be fixed because the attribute is applied on the outer dictionary and not the inner dictionary (which is the problematic one).

Generated at Wed Feb 07 21:38:51 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.