[CSHARP-4587] ArgumentException using custom Dictionary serializer with IReadOnlyDictionary in a projection after upgrading to 2.19 driver Created: 29/Mar/23  Updated: 21/Apr/23

Status: Backlog
Project: C# Driver
Component/s: LINQ3
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Paul Spangler Assignee: Unassigned
Resolution: Unresolved Votes: 2
Labels: triage
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: Zip Archive ConsoleApp1-1.zip    

 Description   

Summary

We're using a custom IBsonSerializationProvider that provides a custom serializer/deserializer for string dictionary keys.

After upgrading to the 2.19 (and 2.19.1) driver with the LINQ3 provider enabled by default, our projections containing IReadOnlyDictionary<string, string> get an ArgumentException.

 

Tested against a standalone 5.0.15 server.

 

How to Reproduce

[^ConsoleApp1.zip]

The attached example includes the connection string and name of the database as arguments in the launchSettings.json. The relevant parts are:

 

BsonSerializer.RegisterSerializationProvider(new KeyEncodingDictionarySerializationProvider());
// <snip>
await collection.Find(filter)
    .Project(Builders<Model>.Projection.Expression(
        m => new Model(m.Id)
        {
            Properties = m.Properties,
        }))
    .SingleAsync();

Where the Model class has a property named Properties of type IReadOnlyDictionary<string, string> and the KeyEncodingDictionarySerializationProvider creates an IBsonSerializer of type DictionarySerializerBase<Dictionary<string, string>?, string, string>.

The result is an ArgumentException (edited a little to reduce verbosity):

Value type of serializer is Dictionary`2[[System.String],[System.String]] and does not match member type IReadOnlyDictionary`2[[System.String],[System.String]]. (Parameter 'serializer')
  Source=MongoDB.Bson
  StackTrace:
   at MongoDB.Bson.Serialization.BsonMemberMap.SetSerializer(IBsonSerializer serializer)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MemberInitExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, MemberInitExpression expression)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, Expression expression)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(TranslationContext context, LambdaExpression lambdaExpression, IBsonSerializer parameterSerializer, Boolean asRoot)
   at MongoDB.Driver.Linq.Linq3Implementation.LinqProviderAdapterV3.TranslateExpressionToProjection[TInput,TOutput](Expression`1 expression, IBsonSerializer`1 inputSerializer, IBsonSerializerRegistry serializerRegistry, ExpressionTranslationOptions translationOptions)
   at MongoDB.Driver.Linq.Linq3Implementation.LinqProviderAdapterV3.TranslateExpressionToFindProjection[TSource,TProjection](Expression`1 expression, IBsonSerializer`1 sourceSerializer, IBsonSerializerRegistry serializerRegistry)
   at MongoDB.Driver.FindExpressionProjectionDefinition`2.Render(IBsonSerializer`1 sourceSerializer, IBsonSerializerRegistry serializerRegistry, LinqProvider linqProvider)
   at MongoDB.Driver.MongoCollectionImpl`1.CreateFindOperation[TProjection](FilterDefinition`1 filter, FindOptions`2 options)
   at MongoDB.Driver.MongoCollectionImpl`1.FindAsync[TProjection](IClientSessionHandle session, FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.<>c__DisplayClass48_0`1.<FindAsync>b__0(IClientSessionHandle session)
   at MongoDB.Driver.MongoCollectionImpl`1.<UsingImplicitSessionAsync>d__107`1.MoveNext()
   at MongoDB.Driver.IAsyncCursorSourceExtensions.<SingleAsync>d__11`1.MoveNext()

 

Additional Background

We only see the ArgumentException when using projections. Doing inserts and finds without projections works just fine. We ran into this issue after upgrading to the 2.19 driver, presumably because of the switch to the LINQ3 provider by default. Manually switching back to the LINQ2 provider avoids the issue.



 Comments   
Comment by Robert Stam [ 29/Mar/23 ]

Thank you for reporting this. I will be looking into it.

Comment by Paul Spangler [ 29/Mar/23 ]

I meant to include in the description that our use of IReadOnlyDictionary in model classes isn't strictly required, but we consider it good practice over using a mutable data structure like Dictionary.

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