在Id过滤期间,MongoDB驱动程序无法将自定义序列化程序强制转换为IBsonSerializer

时间:2018-02-02 11:15:51

标签: c# mongodb mongodb-.net-driver

我正在使用C#编写应用程序。我从MongoDB获取Id文档时遇到了一些问题。

我的ID不是ObjectId,而是Guid。

模型是简单的POCO。

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

在创建存储库实例(静态构造函数)期间,我注册了类映射:

    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);
        });
    }

我还指定了自己的序列化程序:

[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); }
    }
}

现在这是抛出异常的方法:

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();
}

例外是:

  

无法将“MyApp.Repositories.Reporting.Concrete.MyGuidSerializer”类型的对象强制转换为“MongoDB.Bson.Serialization.IBsonSerializer`1 [System.Guid]”。

     

System.InvalidCastException

通常序列化有效。如果我将方法更改为此版本:

    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();
    }

我将得到正确填充的Folder模型。

我做错了什么?

2 个答案:

答案 0 :(得分:0)

您为什么要首先序列化为string

您应该可以通过直接序列化/反序列化到Guid来解决您的问题:

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);
    }

答案 1 :(得分:0)

我不知道为什么但是在更改IBsonSerializer<Guid>的界面之后一切正常。

[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); }
    }
}

一般来说,通用接口会继承IBsonSerializer,所以我无法理解为什么我将IBsonSerializer实现为MyGuidSerializer Unable cast to IBsonSerializer

是的,但是将实施的界面从IBsonSerializer更改为IBsonSerializer<Guid>可以解决问题。

Mongodb.CsharpDriver 2.4.4