3

我们正在使用 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: Ambiguous discriminator 'SubscriberRequest`1'

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

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

无济于事。

我怎样才能正确地满足鉴别器?

4

3 回答 3

3

我自己也遇到了这个。

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

对于您的情况,这样的事情应该可以工作:

BsonClassMap.RegisterClassMap<SubscriberRequest<MessageType1Request>>(cm =>
{
    cm.AutoMap();
    cm.SetDiscriminator("SubscriberRequest`MessageType1Request");
};
BsonClassMap.RegisterClassMap<SubscriberRequest<MessageType2Request>>(cm =>
{
    cm.AutoMap();
    cm.SetDiscriminator("SubscriberRequest`MessageType2Request");
};
于 2016-02-05T09:50:09.213 回答
1

我找到了这个并做了一个小的修改MongoDB C# 驱动程序类型鉴别器,泛型类继承自非泛型基类

按照@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
    }
}
于 2016-02-05T13:14:04.887 回答
0

I think you need something like this: Serialize Documents with the C# Driver - Specifying Known Types

Basically, you need to map all of your known types in order for the discriminator to determine what you want.

BsonClassMap.RegisterClassMap<SubscriberRequest<MessageType1Request>>();
BsonClassMap.RegisterClassMap<SubscriberRequest<MessageType2Request>>();
于 2014-07-09T22:19:59.687 回答