Details
-
Question
-
Resolution: Gone away
-
Unknown
-
None
-
2.14.0
-
None
Description
There seems to be a bug when trying to serialize properties of IReadOnlyList<T> when the property is set to an array of a derived type.
Â
For example, running the following code:
using MongoDB.Bson;
|
using MongoDB.Driver;
|
|
|
var client = new MongoClient(); |
|
|
var database = client.GetDatabase("test"); |
|
|
var collection = database.GetCollection<Farm>("farms"); |
|
|
var farm = new Farm( |
ObjectId.GenerateNewId(),
|
"Farm 1", |
new[] { new Cow(1, "Bob"), new Cow(2, "Alice") } |
);
|
|
|
await collection.InsertOneAsync(farm);
|
|
|
// Exception thrown here
|
var foundFarm = await collection.Find(x => x.Id == farm.Id).FirstAsync();
|
|
|
record Farm(ObjectId Id, string Name, IReadOnlyList<Animal> Animals);
|
|
|
abstract record Animal(int Id); |
|
|
record Cow(int Id, string Name) : Animal(Id); |
|
|
record Pig(int Id, string Name) : Animal(Id); |
Throws the following exception:
Unhandled exception. System.FormatException: An error occurred while deserializing the Animals property of class Farm: Cannot create an abstract class. |
---> System.MemberAccessException: Cannot create an abstract class. |
at System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject(Type type)
|
at System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type)
|
at MongoDB.Bson.Serialization.BsonClassMap.<GetCreator>b__114_2()
|
at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeClass(BsonDeserializationContext context) |
at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) |
at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context) |
at MongoDB.Bson.Serialization.Serializers.EnumerableSerializerBase`2.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) |
at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context) |
at MongoDB.Bson.Serialization.Serializers.ImpliedImplementationInterfaceSerializer`2.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) |
at MongoDB.Bson.Serialization.Serializers.SerializerBase`1.MongoDB.Bson.Serialization.IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) |
at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize(IBsonSerializer serializer, BsonDeserializationContext context)
|
at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeMemberValue(BsonDeserializationContext context, BsonMemberMap memberMap) |
--- End of inner exception stack trace ---
|
at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeMemberValue(BsonDeserializationContext context, BsonMemberMap memberMap) |
at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeClass(BsonDeserializationContext context) |
at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) |
at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context) |
at MongoDB.Driver.Core.Operations.CursorBatchDeserializationHelper.DeserializeBatch[TDocument](RawBsonArray batch, IBsonSerializer`1 documentSerializer, MessageEncoderSettings messageEncoderSettings) |
at MongoDB.Driver.Core.Operations.FindCommandOperation`1.CreateFirstCursorBatch(BsonDocument cursorDocument) |
at MongoDB.Driver.Core.Operations.FindCommandOperation`1.CreateCursor(IChannelSourceHandle channelSource, IChannelHandle channel, BsonDocument commandResult) |
at MongoDB.Driver.Core.Operations.FindCommandOperation`1.ExecuteAsync(RetryableReadContext context, CancellationToken cancellationToken) |
at MongoDB.Driver.Core.Operations.FindOperation`1.ExecuteAsync(RetryableReadContext context, CancellationToken cancellationToken) |
at MongoDB.Driver.Core.Operations.FindOperation`1.ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken) |
at MongoDB.Driver.OperationExecutor.ExecuteReadOperationAsync[TResult](IReadBinding binding, IReadOperation`1 operation, CancellationToken cancellationToken) |
at MongoDB.Driver.MongoCollectionImpl`1.ExecuteReadOperationAsync[TResult](IClientSessionHandle session, IReadOperation`1 operation, ReadPreference readPreference, CancellationToken cancellationToken) |
at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSessionAsync[TResult](Func`2 funcAsync, CancellationToken cancellationToken) |
at MongoDB.Driver.IAsyncCursorSourceExtensions.FirstAsync[TDocument](IAsyncCursorSource`1 source, CancellationToken cancellationToken) |
at Program.<Main>$(String[] args) in C:\dev\kevbite\MongoDbBug\MongoDbBug\MongoDbBug\Program.cs:line 20 |
at Program.<Main>(String[] args)
|
... and generates the following document in the database
{
|
"_id" : ObjectId("61a9036e68774829f484e844"), |
"Name" : "Farm 1", |
"Animals" : [ |
{
|
"_id" : 1, |
"Name" : "Bob" |
},
|
{
|
"_id" : 2, |
"Name" : "Alice" |
}
|
]
|
}
|
As you can see it's missing the discriminator field (`_t`)
I assume it's because the array is of type `Cow[]` instead of `Animal[]`. If we update the code with the following change:
var farm = new Farm( |
ObjectId.GenerateNewId(),
|
"Farm 1", |
new Animal[] { new Cow(1, "Bob"), new Cow(2, "Alice") } |
);
|
The following document is generated
{
|
"_id" : ObjectId("61a905ea132842f1fcf18782"), |
"Name" : "Farm 1", |
"Animals" : [ |
{
|
"_t" : "Cow", |
"_id" : 1, |
"Name" : "Bob" |
},
|
{
|
"_t" : "Cow", |
"_id" : 2, |
"Name" : "Alice" |
}
|
]
|
}
|