【问题标题】:Masstransit configuring a generic consumerMasstransit 配置通用消费者
【发布时间】:2020-05-19 11:31:06
【问题描述】:

我正在使用 MassTransit 在我们现有的应用程序中集成消息传递代理。 我们已经实现了一种具有通用实现的命令处理程序,如下所示:

public class MyCommandHandler: CommandHandlerBase<MyCommand>

现在创建一个通用的 Consumer 相对容易,它会做一些样板化并将工作交给就绪的命令处理程序,从 DI 容器请求。

public class CommandConsumer<TCommand> : IConsumer<TCommand>

然后我可以通过 Microsoft DI 轻松注册:

cfg.AddConsumer<CommandConsumer<MyCommand>>(x => some configuration...);

这一切都很好,所以我继续下一步,即将消费者注册提取到一个常见的帮助方法,这就是我有点难过的地方。该方法(当前)看起来有点像这样

public static IServiceCollection ConfigureMassTransit(this IServiceCollection services, params Type[] consumerTypes)
{
        return 
            services.AddMassTransit(cfg =>
            {
                foreach (var consumerType in consumerTypes)
                {
                    cfg.AddConsumer(consumerType);
                }
                // or cfg.AddConsumers(consumerTypes);
                cfg.AddBus(context => Bus.Factory.CreateUsingRabbitMq(config =>
                {
                    var host = config.Host("localhost", "/",
                        h =>
                        {
                            h.Username("guest");
                            h.Password("guest");
                        });
                    config.ConfigureEndpoints(context);
                }));

            });
    }

这将被称为services.ConfigureMassTransit(typeof(CommandConsumer&lt;MyCommand&gt;)); 这再次有效,但我不知道如何将附加配置添加到注册中;仅在使用通用签名时才可以使用 Action 的重载,当您只有 Type 可用时,您不能直接使用它。我尝试将标记类 CommandConsumer: IConsumer 添加到 CommandConsumer&lt;TCommand&gt; 并制作 CommandConsumerDefinition : ConsumerDefinition&lt;CommandConsumer&gt;,并将上面的内容更改为 cfg.AddConsumer(consumerType, typeof(CommandConsumerDefinition));,但这不起作用,因为永远不会命中 ConfigureConsumer 覆盖。

我应该如何向编译时不知道其类型的消费者添加额外的配置?

【问题讨论】:

  • 在抽象之上构建抽象不是很有趣吗?您可以关注conventional route,它不受支持,但提供了最简洁的集成。如果你坚持创建一个通用的消费者定义,那么我猜也让它通用吧? --祝你好运。

标签: c# dependency-injection masstransit


【解决方案1】:

Chris 的回答让我走上了可行的解决方案。使 CommandConsumerDefinition 泛型允许我在运行时使用反射以相同的方式构造这两种类型。这允许 MassTransit 以预期的方式连接配置。

最后,我还使用了一个“标记”属性来保存命令合同的类型,因此可以发现它们,而不必在启动时作为参数输入。

public static IServiceCollectionConfigurator ConfigureMassTransitConsumers(this IServiceCollectionConfigurator serviceConfigurator, Assembly assembly)
    {
        foreach (var type in assembly.GetTypes())
        {
            var attributes = type.GetCustomAttributes(typeof(RegisterCommandConsumerAttribute), false);
            if (attributes.Length <= 0) continue;
            foreach (var attribute in attributes)
            {
                if (attribute is RegisterCommandConsumerAttribute registerCommandConsumerAttribute)
                {
                    Type consumerType = typeof(CommandConsumer<>).MakeGenericType(registerCommandConsumerAttribute.CommandType);
                    Type consumerDefinitionType = typeof(CommandConsumerDefinition<>).MakeGenericType(registerCommandConsumerAttribute.CommandType);
                    serviceConfigurator.AddConsumer(consumerType, consumerDefinitionType);
                }
            }
        }
        return serviceConfigurator;
    }

由于自动发现,我们已经处于反思领域,所以这似乎是一个可以接受的解决方案。这样我们就可以拥有通用的消费者和定义,而不必为我们拥有的每个命令合约添加一个新类。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 2022-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多