访问单一托管服务中的范围 DbContext

问题描述 投票:0回答:1

我不能简单地注入数据库上下文,所以我必须依赖注入

IServiceScopeFactory
并像这样从注册服务中获取它。

AppDbContext Context()
{
  using IServiceScope scope = Services.CreateScope();
  return scope.ServiceProvider.GetRequiredService<AppDbContext>();
}

当我像这样在其他地方调用它时它不起作用

async Task Seed(int count)
{
  AppDbContext context = Context();
  ...
  await context.AddAsync(new Thing { ... });
  await context.SaveChangesAsync();
}

根据报错信息,处理服务。而且,事实上,因为我将它设置在

using
语句的范围内,所以随着方法的结束,它应该是预期的。我看到两种处理方法。

  1. 以与数据库对话的相同方法请求服务。
  2. 省略上下文的处理,使其在单身人士中保持活力。

我不喜欢他们两个。第一个导致代码冗余。另一个可能会阻止其他范围内的数据库访问。

处理它的更好选择是什么?

最初,我尝试在我的班级内部创建选项并创建数据库访问。但是,当我开始创建迁移时,它停止工作了,因为

dotnet ef migrations add Init
需要在
Program
中注册服务,因此迫使我使用上面的方法获取它。

DbContextOptions<AppDbContext> ContextOptions()
{
  DbContextOptionsBuilder<AppDbContext> builder = new();
  builder.UseInMemoryDatabase("memento");
  //builder.UseSqlServer(a => { });
  return builder.Options;
}
c# dependency-injection singleton backgroundworker dbcontext
1个回答
1
投票

正常的解决方案是围绕需要它的工作创建一个范围。由于您的服务是周期性的,我建议为每个基于时间的调用设置一个范围。这就是我为我的预定服务所做的。

注入

IServiceProvider
后,您可以使用它来创建范围,然后创建您需要的任何“处理器”类型(这反过来会注入
DbContext
):

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
  while (!stoppingToken.IsCancellationRequested)
  {
    using IServiceScope scope = _serviceProvider.CreateScope();
    AppDbContext context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
  }
}

Scopes 的创建速度非常快; ASP.NET 的正常模式是为每个请求创建一个新范围。

© www.soinside.com 2019 - 2024. All rights reserved.