【问题标题】:How can I let Rebus determine an endpoint for an interface and not for an implementation of that interface如何让 Rebus 确定接口的端点而不是该接口的实现
【发布时间】:2013-07-12 07:18:59
【问题描述】:

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

提前致谢!

【问题讨论】:

    标签: rebus


    【解决方案1】:

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

    如果您想利用 Rebus 的现有逻辑,您可以装饰任何选择的策略并使用 keep-looking-at-all-implemented-interfaces-until-one-can-be-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 端点中...

    如果您能告诉我这对您有何影响,我将不胜感激! :)

    【讨论】:

    • 哇,谢谢您的回复!当我找到一些时间并告诉你结果如何时,一定会尝试一下。
    • 嗨!我很好奇 - 你的结果如何?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-20
    • 1970-01-01
    • 2018-09-04
    • 1970-01-01
    • 2019-04-07
    相关资源
    最近更新 更多