Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-1894

InvalidCastException in FieldValueSerializerHelper on implicit type casting

    • Type: Icon: Bug Bug
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • 2.4.3
    • Affects Version/s: 2.4.1
    • Component/s: Linq, Serialization
    • Labels:
      None
    • Environment:
      Windows 10, MongoDB 3.4.0

      Recent driver release (v.2.4.1) has broken my project completely. It seems that the problem is related to the newly added serialization helper (FieldValueSerializerHelper). After updating from version 2.3.0 I got InvalidCastException.

      Unable to cast object of type 'Fulcrum.Int64FulcrumId' to type 'Fulcrum.Ref`1[Fulcrum.TestData.ReferencedExampleEntity]'.
      
      at MongoDB.Driver.FieldValueSerializerHelper.CastingSerializer`2.Serialize(BsonSerializationContext context, BsonSerializationArgs args, TFrom value)
         at MongoDB.Bson.Serialization.Serializers.SerializerBase`1.MongoDB.Bson.Serialization.IBsonSerializer.Serialize(BsonSerializationContext context, BsonSerializationArgs args, Object value)
         at MongoDB.Driver.Linq.Expressions.ISerializationExpressionExtensions.SerializeValues(ISerializationExpression field, Type itemType, IEnumerable values)
         at MongoDB.Driver.Linq.Translators.PredicateTranslator.TranslatePipelineContains(PipelineExpression node)
         at MongoDB.Driver.Linq.Translators.PredicateTranslator.TranslatePipeline(PipelineExpression node)
         at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node)
         at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry)
         at MongoDB.Driver.Linq.Translators.QueryableTranslator.TranslateWhere(WhereExpression node)
         at MongoDB.Driver.Linq.Translators.QueryableTranslator.Translate(Expression node)
         at MongoDB.Driver.Linq.Translators.QueryableTranslator.TranslateGroupBy(GroupByExpression node)
         at MongoDB.Driver.Linq.Translators.QueryableTranslator.Translate(Expression node)
         at MongoDB.Driver.Linq.Translators.QueryableTranslator.TranslatePipeline(PipelineExpression node)
         at MongoDB.Driver.Linq.Translators.QueryableTranslator.Translate(Expression node)
         at MongoDB.Driver.Linq.Translators.QueryableTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry, ExpressionTranslationOptions translationOptions)
         at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.Translate(Expression expression)
         at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.Execute(Expression expression)
         at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.Execute[TResult](Expression expression)
         at System.Linq.Queryable.Count[TSource](IQueryable`1 source)
      

      We are using active-record approach and lazy-load reference wrappers that can be casted to Id using implicit operator conversion.

      var foo = new Foo();
      foo.Save();
      var bar = new Bar() { F = foo};
      bar.Save();
      
      //throws InvalidCastException
      Bar.Collection.AsQueryable().Where(b=>b.F == foo.Id); 
      

      FieldValueSerializerHelper.CastingSerializer is trying to convert value using boxing conversion. It will always fail if destination type does not match source type (the only exclusion is the situation when source type inherits from destination type).

      _serializer.Serialize(context, args, (TTo)(object)value);
      

      Boxing conversion omits user-defined type conversion therefor custom TypeConverter nor implicit operator conversions won't work.

      Please add support for user-defined implicit type casting to the predicate translator.

      I've prepared pull request that implements the requested feature. It might help with CSHARP-1890, CSHARP-1891 if I'm not mistaken. This approach will also allow implicit casting of primitive types out of the box, for example:

      //Int32 (1) will be automatically casted to string value ("1")
      SomeCollection<Example>().AsQueryable().Where(x=>x.StringValue == (object)1);
      //{"StringValue": "1"}
      

            Assignee:
            robert@mongodb.com Robert Stam
            Reporter:
            kreig Vyacheslav Stroy
            Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: