如何反转/注入依赖 - MassTransit Consumer

时间:2017-12-01 00:34:09

标签: c# reflection dependency-injection masstransit constructor-injection

我正在研究一个项目,一切正常,但我有一个紧密耦合的依赖,我不明白如何反转/注入。

问题出在我的Consumer类中,它将接收命令消息以启动进程,该进程是全局消息队列服务项目的一部分,例如, 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的签名,因为这实际上是IConsumer的{​​{1}}接口的实现。

我想我想要的是一种反转/注入该依赖项的方法,以便我的全局MassTransit项目不依赖于调用它的项目。我想我对反转/注射有一些误解,但我不确定如何表达我的缺点。也许我想要的是不可能的。我知道我无法修改接口实现,但如果以下内容有效,我会很酷,但由于MQ.services是MassTransit接口的实现,我不认为我可以注入一个匿名函数来自我的通话班:

Consume

我设法通过使用反射并将此逻辑放在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 - &gt;参考App.SubscriberConsole

项目:App.Services.Subscriber - &gt;参考文献App.Services.Subscriber,et al

项目MyCompany.MQ.Services.Consumer - &gt;参考MyCompany.MQ.Services.Consumer - &gt;实现MassTransit

1 个答案:

答案 0 :(得分:2)

我不确定你为什么考虑注入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));
    });
});

您可以在端点in the documentation上找到消费者配置方法的更多重载。

另外一件事。你有严重的Serilog问题。您为每条消息()创建记录器配置。这个不对。您应该在应用程序入口点创建一次的记录器配置

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