Reputation: 71
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
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
Reputation: 385
Why are you trying to serialize to string
in 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