我们正在使用Bson在RabbitMq Rpc客户端服务器调用的任一侧进行序列化/反序列化。我们已按照此处的建议实现了SimpleRpcClient / Server:
但是,我们的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));
});
无济于事。
我如何恰当地满足鉴别器?
答案 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
}
}