包含泛型的类型的BsonClassMap

时间:2013-11-08 21:50:48

标签: c# serialization rabbitmq mongodb-.net-driver bson

我们正在使用Bson在RabbitMq Rpc客户端服务器调用的任一侧进行序列化/反序列化。我们已按照此处的建议实现了SimpleRpcClient / Server:

https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v3.1.5/rabbitmq-dotnet-client-3.1.5-client-htmldoc/html/type-RabbitMQ.Client.MessagePatterns.SimpleRpcServer.html

但是,我们的Subscription对象实现如下:

public class SubscriberRequest<TKey> : SubscriberRequest
{
    public TKey[] Keys { get; set; }

    public SubscriberRequest(){}

    public SubscriberRequest(IEnumerable<TKey> keys) : base()
    {
        this.Keys = keys.ToArray();
        this.Hostname = Dns.GetHostName();
    }
}

public class SubscriberRequest
{
    public static SubscriberRequest Default = new SubscriberRequest() { Hostname = Dns.GetHostName() };

    public string Hostname { get; set; }
}

允许我们在打字的庄园中来回发送请求响应对象。当我们的序列化程序仅负责处理一种类型的“请求”对象时,这似乎工作得很好。

BsonClassMap.LookupClassMap(typeof(SubscriberRequest<MessageType1Request>));

但是,当我们尝试将序列化程序用于多种类型的请求对象时,我似乎无法设置足够的ClassMap以满足反序列化程序。

BsonClassMap.LookupClassMap(typeof(SubscriberRequest<MessageType1Request>));
BsonClassMap.LookupClassMap(typeof(SubscriberRequest<MessageType2Request>));

我一直得到一个MongoDB.Bson.BsonSerializationException:歧义判别器'SubscriberRequest`1'

我试图明确地告诉BsonClassMap如何处理这个:

        BsonClassMap.RegisterClassMap<SubscriberRequest<MessageType1Request>>(cm =>
            {
                cm.MapCreator(p => new SubscriberRequest<MessageType1Request>(p.Keys));
            }); 

无济于事。

我如何恰当地满足鉴别器?

3 个答案:

答案 0 :(得分:1)

我自己就碰到了这个。

解决方案是覆盖每个泛型类型的鉴别器,因此在序列化时,它们会获得唯一值。

对于你的情况,这样的事情应该有效:

BsonClassMap.RegisterClassMap<SubscriberRequest<MessageType1Request>>(cm =>
{
    cm.AutoMap();
    cm.SetDiscriminator("SubscriberRequest`MessageType1Request");
};
BsonClassMap.RegisterClassMap<SubscriberRequest<MessageType2Request>>(cm =>
{
    cm.AutoMap();
    cm.SetDiscriminator("SubscriberRequest`MessageType2Request");
};

答案 1 :(得分:0)

我认为你需要这样的东西:Serialize Documents with the C# Driver - Specifying Known Types

基本上,您需要映射所有已知类型,以便鉴别器确定您想要的内容。

BsonClassMap.RegisterClassMap<SubscriberRequest<MessageType1Request>>();
BsonClassMap.RegisterClassMap<SubscriberRequest<MessageType2Request>>();

答案 2 :(得分:0)

我发现了这个并进行了一些小修改MongoDB C# driver type discriminators with generic class inheriting from non-generic base class

根据@Bruce Nielsen的建议设置识别器不是很灵活

public class DiscriminatorConvention<T> : IDiscriminatorConvention
{
    public string ElementName => "_t";

    public Type GetActualType(IBsonReader bsonReader, Type nominalType)
    {
        if (!typeof(T).IsAssignableFrom(nominalType))
                throw new Exception($"Cannot use DiscriminatorConvention<{typeof(T).Name}> for type " + nominalType);

        var ret = nominalType;

        var bookmark = bsonReader.GetBookmark();
        bsonReader.ReadStartDocument();
        if (bsonReader.FindElement(ElementName))
        {
            var value = bsonReader.ReadString();
            ret = Type.GetType(value);

            if (ret == null)
                throw new Exception("Could not find type from " + value);

            if (!typeof(T).IsAssignableFrom(ret) && !ret.IsSubclassOf(typeof(T)))
                throw new Exception("type is not an IRestriction");
        }

        bsonReader.ReturnToBookmark(bookmark);

        return ret;
    }

    public BsonValue GetDiscriminator(Type nominalType, Type actualType)
    {
        if (nominalType != typeof(Setting))
            throw new Exception($"Cannot use {GetType().Name} for type " + nominalType);

        return actualType.AssemblyQualifiedName; // ok to use since assembly version is ignored when deserialized
    }
}