当我发送由AutoMapper.Mapper.DynamicMap()创建的实例时,我遇到一个错误,Rebus似乎想确定DynamicMap返回的代理类型的终结点。这个实例将包含一个T的实现,假设T是一个接口类型。
有没有一种方法可以让Rebus为接口类型T而不是DynamicMap()返回的实现类型确定端点?
我试着玩IDetermineMessageOwnership,但到目前为止运气不佳。
public static void Send<T>(this IBus bus, object source)
{
var message = Mapper.DynamicMap<T>(source);
bus.Send<T>(message);
}
提前感谢!
当然!在您的情况下,您可以创建自己的IDetermineMessageOwnership
实现,这是Rebus用于将消息类型映射到端点的服务。
如果你想利用Rebus现有的逻辑,你可以装饰任何选择的策略,并用扩展它。继续查看所有实现的接口,直到可以映射一个策略,如下所示:
Configure.With(adapter)
.(...)
.MessageOwnership(o => o.FromRebusConfigurationSection())
.Decorators(d => d.AddDecoration(DecorateOwnershipMapping)))
.CreateBus()
.Start();
其中DecorateOwnershipMapping
将在任何配置的上面安装一个装饰器,如下所示:
void DecorateOwnershipMapping(ConfigurationBackbone b)
{
b.DetermineMessageOwnership = new CustomizedEndpointMapper(b.DetermineMessageOwnership);
}
一种可能的实现方式可能是这样的:
class CustomizedEndpointMapper : IDetermineMessageOwnership
{
readonly IDetermineMessageOwnership wrappedEndpointMapper;
public CustomizedEndpointMapper(IDetermineMessageOwnership wrappedEndpointMapper)
{
this.wrappedEndpointMapper = wrappedEndpointMapper;
}
public string GetEndpointFor(Type messageType)
{
var mappingCandidates = new[] {messageType}
.Concat(messageType.GetInterfaces())
.ToList();
foreach (var typeToTry in mappingCandidates)
{
try
{
return wrappedEndpointMapper.GetEndpointFor(typeToTry);
}
catch{}
}
throw new InvalidOperationException(string.Format("Could not determine the owner of message of type {0} - attempted to map the following types: {1}",
messageType, string.Join(", ", mappingCandidates)));
}
}
从而在尝试确定拥有端点时迭代具体类型以及所有继承的接口类型。
在您的情况下,我相信在确定消息所有者时,这将完美地工作。唯一的问题是序列化程序很可能会抱怨,因为在收到消息时无法再次识别动态生成的类型。
因此,这个技巧还需要自定义序列化程序。如果您使用(默认)JSON序列化程序,您可能会使用一些自定义解析器,如
Configure.With(...)
.(...)
.Serialization(s => s.UseJsonSerializer()
.AddNameResolver(CustomNameResolver)
.AddTypeResolver(CustomTypeResolver))
.(...)
其中CustomNameResolver
和CustomTypeResolver
是必须负责将类型映射到类型名称并将类型名称映射到然后可以反序列化为的类型的方法。为了使用AutoMapper,您可能需要使用
a) 以某种方式使用AutoMapper查找接收到的消息的类型,并从CustomTypeResolver
或返回该类型
b) 自定义序列化程序,使AutoMapper以某种方式参与生成要返回的对象
但我必须承认,我不确定最后一部分是否会顺利上演。
最后一点:如果你成功地完成了这项工作,我建议你在RebusConfigurer
上把你的配置咒语打包成一个可重复使用的扩展方法,这样你的端点就可以进行
Configure.With(...)
.(...)
.UseMyFunkyAutoMapperMessagesJustTheWayILikeIt()
.CreateBus().Start();
在你所有的Rebus终点。。。
如果你能让我知道这对你来说是怎么回事,我将不胜感激!:)