3

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

提前致谢!

4

1 回答 1

1

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

如果您想利用 Rebus 的现有逻辑,您可以装饰任何选择的策略并使用keep-looking-at-all-implemented-interfaces-until-one-can-be-mapped策略对其进行扩展,如下所示:

Configure.With(adapter)
         .(...)
         .MessageOwnership(o => o.FromRebusConfigurationSection())
         .Decorators(d => d.AddDecoration(DecorateOwnershipMapping)))
         .CreateBus()
         .Start();

whereDecorateOwnershipMapping将在任何配置的顶部安装装饰器,如下所示:

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

whereCustomNameResolverCustomTypeResolverare 方法必须负责将类型映射到类型名称,并将类型名称映射到可以反序列化的类型。为了使用 AutoMapper 进行这项工作,您可能需要

a) 以某种方式使用 AutoMapper 查找接收到的消息的类型并从返回该类型CustomTypeResolver,或者

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

但我必须承认,我不确定最后一部分是否会顺利进行。

最后一点:如果你成功完成了这项工作,我建议你将你的配置拼写成一个可重用的扩展方法,RebusConfigurer这样你的端点就可以运行

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

在您所有的 Rebus 端点中...

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

于 2013-07-16T22:05:54.183 回答