如何反转/注入依赖性-MassTransit消费者



我正在从事一个项目,一切都在起作用,但是我有一个紧密耦合的依赖性,我不明白如何反转/注射。

问题在我的消费类中,该类将接收命令消息以启动一个流程,这是全球消息队列服务项目的一部分,例如MyCompany.MQ.Services,但对命令消息告诉其开始的过程的依赖性紧密,例如:

public Task Consume(ConsumeContext<MyMessageInterface> context)
{
    logger = new LoggerConfiguration()
        .WriteTo.Console()
        .CreateLogger();
    try
    {
        TightCoupleProcess tcp = new TightCoupleProcess(context);
        logger.Information("{Blah}, {Blah}, {Blah}", context.Message.exampleVar1, context.Message.exampleVar2, context.Message.exampleVar3);
        tcp.StartProcess();
        return Task.CompletedTask;
    }
    catch (Exception ex)
    {
        return Task.FromException(ex);
    }
}

Task Consume是MassTransit的一部分,我无法修改Consume的签名,因为这实际上是MassTransitIConsumer接口的实现。

我想我想要的是一种反转/注入该依赖关系的方法,以便我的全局MQ.services项目不取决于该项目的调用。我认为我对反转/注入有一些误解,但我不确定如何表达自己的缺点。也许我想要的是不可能的。我知道我无法修改接口实现,但是如果以下功能有效,我会很酷,但是由于Consume是MassTransit接口的实现,我认为我无法从调用类中注入匿名功能:

public Task Consume(ConsumeContext<MyMessageInterface> context, AnonFunc() func)
{ 
    try
    {
        func(context)
        logger.Information("{Blah}, {Blah}, {Blah}", context.Message.exampleVar1, context.Message.exampleVar2, context.Message.exampleVar3);
        return Task.CompletedTask;
    }
    catch (Exception ex)
    {
        return Task.FromException(ex);
    }
}

我设法通过使用反射并将此逻辑放入MQ.Services项目中,以解决其他依赖项,例如消息类型定义,这使我能够将TightCoupleProcess所有相关代码保留在MQ.serives项目之外,例如:

    public void PublishMessage(object msg)
    {
        MethodInfo method = this.GetType().GetMethod("InvokePublish");
        MethodInfo generic = method.MakeGenericMethod(msg.GetType());
        generic.Invoke(this, new object[] { msg });
    }
    public void InvokePublish<T>(object msg)
    {
        Task.Run(async () =>
        {
            await busControl.Publish(msg);
        }).Wait();

    }

,但是我不能为Consumer应用类似的策略,因为我已经提到过的限制,而且我敢肯定是一种健康的无知剂量。

如果有人会有人指向正确的方向?

更多信息:

项目:App.SubscriberConsole->参考App.Services.Subscriber

项目:App.Services.Subscriber->参考MyCompany.MQ.Services.Consumer等人

项目MyCompany.MQ.Services.Consumer->参考MassTransit->实现MassTransit.IConsumer

我不确定为什么要考虑将其注入Consume方法。方法签名来自接口,您无法更改它。

您应该注入消费类构造函数。考虑注入工厂代表是正确的。

public class MyMessageConsumer : IConsumer<MyMessage>
{
    private readonly Func<IConsumeContext<MyMessage>, TightCoupleProcess> factory;
    public MyMessageConsumer(Func<IConsumeContext<MyMessage>, TightCoupleProcess> factory)
    {
        _factory = factory;
    }
    public Task Consume(ConsumeContext<MyMessage> context)
    {
        var tcp = _factory(context);
        tcp.StartProcess();
        return Task.CompletedTask;
    }
}

然后您像这样进行配置:

Func<IConsumeContext<MyMessage>, TightCoupleProcess> factory = c => new TightCoupleProcess(c);
var busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    var host = cfg.Host(new Uri("rabbitmq://localhost/"), h =>
    {
        h.Username("guest");
        h.Password("guest");
    });
    cfg.ReceiveEndpoint(host, "customer_update_queue", e =>
    {
        e.Consumer<MyMessageConsumer>(() => new MyMessageConsumer(factory));
    });
});

您可以在文档中的端点上找到更多用于消费者配置方法的过载。

另外一件事。您对Serilog有严重的问题。您为每个消息创建Logger Configuration ,您可以使用。这个不对。您应该在应用程序输入点中创建Logger Configuration

然后,您要么注入记录器,要么使用全局Log对象,或使用MassTransit.SerilogIntegration软件包并在消费者中使用MassTransit Logggging。

最新更新