DI 与大众运输消费者和简单注射器的问题
DI woes with Mass Transit consumer and Simple Injector
我有一个 .net 核心网站 api,我一直在尝试向其中添加公共交通消费者。消费者依赖于服务。该服务已注册到 Simple Injector 容器。
container.Register<IMyService, MyService>(Lifestyle.Scoped);
该服务又依赖于使用 IServiceCollection.AddDbContext 添加的 DBContext,然后交叉连接:
Container.CrossWire<MyDbContext>(app);
我已经像这样将服务添加到消费者的构造函数中:
public AddMyCommandConsumer(IMyService service)
{
_service = service;
}
所以我的下一步是设置终点。首先尝试:
cfg.ReceiveEndpoint(host, options.MyQueue, e =>
{
var service = container.GetService<IMyService>();
e.Consumer(() => new AddMyCommandConsumer(service));
}
由于服务是异步作用域这一事实而惨遭失败。 Simple Injector 不喜欢那样。所以经过一番挖掘,我想出了第二次迭代:
cfg.ReceiveEndpoint(host, options.MyQueue, e =>
{
using (AsyncScopedLifestyle.BeginScope(container))
{
var service = container.GetService<IMyService>();
e.Consumer(() => new AddMyCommandConsumer(service));
}
}
这更进一步,创建了消费者,并调用了 consume 方法,但是只要我使用该服务并且需要 DBContext,简单注入器就会抱怨 DBContext 已被释放。如果我删除 using 语句然后它工作,但范围永远不会被释放。
然后我查看了 MassTransit.SimpleInjector nuget 包。没有文档,也没有我能找到的例子,但经过一番挖掘,我想到了这个:
var consumerFactory = new ScopeConsumerFactory<AddMyCommandConsumer>(new
SimpleInjectorConsumerScopeProvider(container));
e.Consumer(consumerFactory);
Mass Transit 尝试创建消费者,但这次失败了,因为 Simple Injector 无法创建服务,即使它已在容器中注册。正如我上面所说,最后一次尝试有点猜测,没有文档或示例。老实说,我认为即使我能正常工作,我最终也会遇到与上面相同的 DBContext 问题。
有什么想法吗?
添加对 MassTransit.SimpleInjector 包的引用,然后在您的接收端点中,使用以下方式配置消费者:
cfg.ReceiveEndpoint("queue_name", e =>
{
e.Consumer<AddMyCommandConsumer>(container);
});
扩展方法将正确配置作用域提供者并添加消费者工厂以从容器中拉取。您的消费者应该注册为 AsyncScoped,以便它正确处理 async/await(MT 大量构建在 TPL 上)。
container.Register<AddMyCommandConsumer>(Lifestyle.Scoped);
此外,我认为有一个容器选项可以将异步生活方式指定为默认值。
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
希望这对您有所帮助,您遇到的任何其他错误都可能与您的服务或 DbContext 的注册方式有关。
我有一个 .net 核心网站 api,我一直在尝试向其中添加公共交通消费者。消费者依赖于服务。该服务已注册到 Simple Injector 容器。
container.Register<IMyService, MyService>(Lifestyle.Scoped);
该服务又依赖于使用 IServiceCollection.AddDbContext 添加的 DBContext,然后交叉连接:
Container.CrossWire<MyDbContext>(app);
我已经像这样将服务添加到消费者的构造函数中:
public AddMyCommandConsumer(IMyService service)
{
_service = service;
}
所以我的下一步是设置终点。首先尝试:
cfg.ReceiveEndpoint(host, options.MyQueue, e =>
{
var service = container.GetService<IMyService>();
e.Consumer(() => new AddMyCommandConsumer(service));
}
由于服务是异步作用域这一事实而惨遭失败。 Simple Injector 不喜欢那样。所以经过一番挖掘,我想出了第二次迭代:
cfg.ReceiveEndpoint(host, options.MyQueue, e =>
{
using (AsyncScopedLifestyle.BeginScope(container))
{
var service = container.GetService<IMyService>();
e.Consumer(() => new AddMyCommandConsumer(service));
}
}
这更进一步,创建了消费者,并调用了 consume 方法,但是只要我使用该服务并且需要 DBContext,简单注入器就会抱怨 DBContext 已被释放。如果我删除 using 语句然后它工作,但范围永远不会被释放。
然后我查看了 MassTransit.SimpleInjector nuget 包。没有文档,也没有我能找到的例子,但经过一番挖掘,我想到了这个:
var consumerFactory = new ScopeConsumerFactory<AddMyCommandConsumer>(new
SimpleInjectorConsumerScopeProvider(container));
e.Consumer(consumerFactory);
Mass Transit 尝试创建消费者,但这次失败了,因为 Simple Injector 无法创建服务,即使它已在容器中注册。正如我上面所说,最后一次尝试有点猜测,没有文档或示例。老实说,我认为即使我能正常工作,我最终也会遇到与上面相同的 DBContext 问题。
有什么想法吗?
添加对 MassTransit.SimpleInjector 包的引用,然后在您的接收端点中,使用以下方式配置消费者:
cfg.ReceiveEndpoint("queue_name", e =>
{
e.Consumer<AddMyCommandConsumer>(container);
});
扩展方法将正确配置作用域提供者并添加消费者工厂以从容器中拉取。您的消费者应该注册为 AsyncScoped,以便它正确处理 async/await(MT 大量构建在 TPL 上)。
container.Register<AddMyCommandConsumer>(Lifestyle.Scoped);
此外,我认为有一个容器选项可以将异步生活方式指定为默认值。
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
希望这对您有所帮助,您遇到的任何其他错误都可能与您的服务或 DbContext 的注册方式有关。