在RabbitMQ Consumer中使用DbContext(Singleton Service)

Dan*_*ndy 6 .net c# rabbitmq asp.net-core

我有一个工作正常的RabbitMQ Singleton,但是当消息到达时它依赖于作用域服务:

consumer.Received += _resourcesHandler.ProcessResourceObject; //Scoped Service
Run Code Online (Sandbox Code Playgroud)

我的服务注册如下:

services.AddScoped<IHandler, Handler>();
services.AddSingleton<RabbitMqListener>();
Run Code Online (Sandbox Code Playgroud)

作用域服务构造函数使用DI作为Db上下文:

private readonly ApplicationDbContext _appDbContext;

public ResourcesHandler(ApplicationDbContext appDbContext)
{
    _appDbContext = appDbContext;
}
Run Code Online (Sandbox Code Playgroud)

此作用域服务调用Db上下文,以便在收到消息时将属性插入数据库.

但是,由于作用域服务具有不同的生命周期,因此启动失败.

有一个更好的方法吗?我可以使作用域服务成为单例,但后来我遇到了使用DbContext作为依赖的问题.

DI中用于在单例服务中调用dbContext的"协议"是什么?

我可以使用一个using语句来确保它被丢弃,但是我必须使用DI来传递DbContextOptions.这是实现这一目标的唯一途径吗?

Evk*_*Evk 8

一种方法是自己创建范围.通常,asp.net核心会在请求开始时为您创建范围,并在请求结束时关闭范围.但在您的情况下 - rabbitmq消息消费与http请求完全无关.但是,您可以说,每个消息处理都代表其自己的范围.

在这种情况下,注入IServiceProviderRabbitMqListener(表示为_provider下面私有字段),然后:

private void OnMessageReceived(Message message) {
    using (var scope = _provider.CreateScope()) {
        var handler = scope.ServiceProvider.GetRequiredService<IHandler>();
        handler.ProcessResourceObject(message);
    }
}
Run Code Online (Sandbox Code Playgroud)

替代方案可以是在容器中注册ApplicationDbContext 工厂(除了常规范围的注册).工厂将返回新的实例,ApplicationDbContext并且调用者有责任处置它.例如:

services.AddSingleton<Func<ApplicationDbContext>>(() =>
{
    var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
    optionsBuilder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
    return new ApplicationDbContext(optionsBuilder.Options);
});
Run Code Online (Sandbox Code Playgroud)

然后你可以注册IHandler为singleton(并且不像现在那样作用域)并Func<ApplicationDbContext>在其构造函数中注入:

private readonly Func<ApplicationDbContext> _appDbContextFactory;

public ResourcesHandler(Func<ApplicationDbContext> appDbContextFactory)
{
    _appDbContextFactory = appDbContextFactory;
}
Run Code Online (Sandbox Code Playgroud)

然后,只要您需要在处理程序中处理消息 - 您自己管理上下文:

using (var context = _appDbContextFactory()) {
    // do stuff
}
Run Code Online (Sandbox Code Playgroud)