sebcza
sebcza

Reputation: 71

MongoDB driver unable cast custom serializer to IBsonSerializer during filter by Id

I am working on an application in C#. I have some problem getting a document by Id from MongoDB.

My Id is not ObjectId but Guid.

Model is simple POCO.

public class Folder
{
        public Guid Id { get; set; }
        public int OrgId { get; set; }
        // rest props is not important
}

During creation of the repository instance (static constructor), I register class map:

    static MongoDBFolderRepository()
    {
        Init();
    }

    private static void Init()
    {
        var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
        ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);

        BsonClassMap.RegisterClassMap<Folder>(cm =>
        {
            cm.AutoMap();
            cm.MapIdMember(c => c.Id).SetSerializer(new MyGuidSerializer());
            cm.SetIgnoreExtraElements(true);
        });
    }

And I have also specified my own serializer:

[BsonSerializer(typeof(MyGuidSerializer))]
public class MyGuidSerializer : IBsonSerializer
{
    public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        return Guid.Parse(BsonSerializer.Deserialize<string>(context.Reader));
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        BsonSerializer.Serialize(context.Writer, value.ToString());
    }

    public Type ValueType
    {
        get { return typeof(Guid); }
    }
}

Now this is the method which throwing an exception:

public async Task<Folder> GetFolderAsync(Guid folderId)
{
    var database = MongoDBHelper.GetDatabase();
    var collection = database.GetCollection<Folder>(CollectionName);
    return await collection.Find(Builders<Folder>.Filter.Eq(x => x.Id, folderId)).SingleAsync();
}

Exception is:

Unable to cast object of type 'MyApp.Repositories.Reporting.Concrete.MyGuidSerializer' to type 'MongoDB.Bson.Serialization.IBsonSerializer`1[System.Guid]'.

System.InvalidCastException

Generally serialization works. If I change method to this version:

    public async Task<Folder> GetFolderAsync(Guid folderId)
    {
        var database = MongoDBHelper.GetDatabase();
        var collection = database.GetCollection<Folder>(CollectionName);
        return await collection.Find(Builders<Folder>.Filter.Eq("_id", folderId.ToString())).SingleAsync();
    }

I will got in return correctly filled Folder model.

What did I do wrong ?

Upvotes: 2

Views: 5121

Answers (2)

sebcza
sebcza

Reputation: 71

I don't know why but after change interface to IBsonSerializer<Guid> all works.

[BsonSerializer(typeof(MyGuidSerializer))]
public class MyGuidSerializer : IBsonSerializer<Guid>
{
    public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        return Guid.Parse(BsonSerializer.Deserialize<string>(context.Reader));
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, Guid value)
    {
        BsonSerializer.Serialize(context.Writer, value.ToString());
    }

    Guid IBsonSerializer<Guid>.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        return Guid.Parse(BsonSerializer.Deserialize<string>(context.Reader));
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        BsonSerializer.Serialize(context.Writer, value.ToString());
    }

    public Type ValueType
    {
        get { return typeof(Guid); }
    }
}

Generally generic interface inherit IBsonSerializer, so I can't understand why if I implemented IBsonSerializer as MyGuidSerializer I got Unable cast to IBsonSerializer.

Yeah ok but change implemented interface from IBsonSerializer to IBsonSerializer<Guid> resolve problem.

Mongodb.CsharpDriver 2.4.4

Upvotes: 5

marcofo88
marcofo88

Reputation: 385

Why are you trying to serialize to stringin the first place?

You should be able to solve your issue by just serializing/deserializing to Guid directly:

public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, Guid value)
    {
        var data = new BsonBinaryData(value);
        context.Writer.WriteBinaryData(data);
    }

public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        return BsonSerializer.Deserialize<Guid>(context.Reader);
    }

Upvotes: 1

Related Questions