如何让Rebus确定接口的端点,而不是该接口的实现

时间:2013-07-12 07:19:00

标签: rebus

当我发送由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);
}

提前致谢!

1 个答案:

答案 0 :(得分:1)

当然!在您的情况下,您可以创建自己的IDetermineMessageOwnership实现,这是Rebus用于将消息类型映射到端点的服务。

如果您想利用Rebus现有的逻辑,您可以修饰任何选择的策略并使用 keep-looking-at-all-implemented-interfaces-extend-until-one-can-to-mapped来扩展它。 em>策略如此:

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))
    .(...)

其中CustomNameResolverCustomTypeResolver是必须将类型映射到类型名称并将类型名称映射到可以反序列化的类型的方法。为了使其与AutoMapper一起使用,您可能需要

a)以某种方式使用AutoMapper查找收到的消息的类型并从CustomTypeResolver

返回该类型

b)自定义序列化程序,让AutoMapper以某种方式参与生成要返回的对象

但我必须承认,我不确定最后一部分是否能顺利播出。

最后一点:如果你成功完成了这项工作,我建议你在RebusConfigurer上将你的配置法术打包成一个可重复使用的扩展方法,以便你的终点可以去

Configure.With(...)
    .(...)
    .UseMyFunkyAutoMapperMessagesJustTheWayILikeIt()
    .CreateBus().Start();

在所有Rebus终端中......

如果你能让我知道这对你有什么影响,我将不胜感激! :)