如何使用来自 Singleton 的 Scoped 服务?

我应该如何注射(使用。NET Core 的内置依赖注入库 ms.DI)将一个 DbContext实例转换为一个单例实例?在我的特殊情况下,单例是一个 IHostedService

我试过什么

我当前让我的 IHostedService类在构造函数中接受一个 MainContext(从 DbContext派生)实例。

当我运行应用程序时,我得到:

不能使用来自单例的范围服务‘ Microsoft. EntityFrameworkCore.DbContextOptions’‘ Microsoft. Extensions.Hosting.IHostedService’。

因此,我尝试通过指定:

services.AddDbContext<MainContext>(options =>
options.UseSqlite("Data Source=development.db"),
ServiceLifetime.Transient);

在我的 Startup课上。

但是错误仍然是相同的,即使根据 解决了 Github 的问题,传递的 DbContextOptions应该具有在 AddDbContext调用中指定的相同生存期。

我不能使数据库上下文成为单例,否则对它的并发调用会产生并发异常(由于数据库上下文不能保证是线程安全的)。

55575 次浏览

在托管服务内部使用服务的一个好方法是在需要时创建一个范围。这允许将服务/db 上下文等与它们所设置的生存期配置一起使用。理论上,不创建作用域可能导致创建单例 DbContext 和不正确的上下文重用(使用 DbContext 池的 EF Core 2.0)。

为此,需要注入一个 IServiceScopeFactory并在需要时使用它创建作用域。然后从此范围解析所需的任何依赖项。这也允许你将自定义服务注册为作用域依赖关系,如果你想将逻辑移出宿主服务,并使用宿主服务仅仅触发一些工作(例如,定期触发一个任务-这将定期创建作用域,在这个作用域中创建任务服务,同时注入一个 db 上下文)。

public class MyHostedService : IHostedService
{
private readonly IServiceScopeFactory scopeFactory;


public MyHostedService(IServiceScopeFactory scopeFactory)
{
this.scopeFactory = scopeFactory;
}


public void DoWork()
{
using (var scope = scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();
…
}
}
…
}

您可以在构造函数中添加 create Scope,如下所示:

 public ServiceBusQueueListner(ILogger<ServiceBusQueueListner> logger, IServiceProvider serviceProvider, IConfiguration configuration)
{
_logger = logger;
_reportProcessor = serviceProvider.CreateScope().ServiceProvider.GetRequiredService<IReportProcessor>();
_configuration = configuration;
}

一定要加

using Microsoft.Extensions.DependencyInjection;