如何 invert/inject 依赖 - MassTransit Consumer
How to invert/inject dependency - MassTransit Consumer
我正在做一个项目,一切正常,但我有一个紧密耦合的依赖项,我不知道如何 invert/inject。
问题出在我的 Consumer class 中,它将接收命令消息以启动一个进程,该进程是全局消息队列服务项目的一部分,例如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
的签名,因为它实际上是 MassTransit
的 IConsumer
接口的实现。
我想我想要的是一种 invert/inject 依赖关系的方法,这样我的全局 MQ.services
项目就不会依赖于调用它的项目。我想我对 inversion/injection 有一些误解,但我不确定如何表达我的缺点。也许我想要的是不可能的。我知道我不能修改接口实现,但如果像下面这样的东西有效,我会很酷,但由于 Consume
是 MassTransit 接口的实现,我认为我不能注入匿名函数来自我的电话 class:
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
方法。方法签名来自接口,您无法更改它。
您应该在消费者 class 构造函数中注入。考虑注入工厂代表是正确的。
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 有严重的问题。您为您使用的每条消息创建记录器配置 。这是不对的。您应该在应用程序入口点创建记录器配置 once。
然后,您要么注入您的记录器,要么使用全局 Log
对象,或者使用 MassTransit.SerilogIntegration
包并使用 MassTransit 记录您的消费者。
我正在做一个项目,一切正常,但我有一个紧密耦合的依赖项,我不知道如何 invert/inject。
问题出在我的 Consumer class 中,它将接收命令消息以启动一个进程,该进程是全局消息队列服务项目的一部分,例如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
的签名,因为它实际上是 MassTransit
的 IConsumer
接口的实现。
我想我想要的是一种 invert/inject 依赖关系的方法,这样我的全局 MQ.services
项目就不会依赖于调用它的项目。我想我对 inversion/injection 有一些误解,但我不确定如何表达我的缺点。也许我想要的是不可能的。我知道我不能修改接口实现,但如果像下面这样的东西有效,我会很酷,但由于 Consume
是 MassTransit 接口的实现,我认为我不能注入匿名函数来自我的电话 class:
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
方法。方法签名来自接口,您无法更改它。
您应该在消费者 class 构造函数中注入。考虑注入工厂代表是正确的。
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 有严重的问题。您为您使用的每条消息创建记录器配置 。这是不对的。您应该在应用程序入口点创建记录器配置 once。
然后,您要么注入您的记录器,要么使用全局 Log
对象,或者使用 MassTransit.SerilogIntegration
包并使用 MassTransit 记录您的消费者。