我不能简单地注入数据库上下文,所以我必须依赖注入
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
语句的范围内,所以随着方法的结束,它应该是预期的。我看到两种处理方法。
我不喜欢他们两个。第一个导致代码冗余。另一个可能会阻止其他范围内的数据库访问。
处理它的更好选择是什么?
最初,我尝试在我的班级内部创建选项并创建数据库访问。但是,当我开始创建迁移时,它停止工作了,因为
dotnet ef migrations add Init
需要在Program
中注册服务,因此迫使我使用上面的方法获取它。
DbContextOptions<AppDbContext> ContextOptions()
{
DbContextOptionsBuilder<AppDbContext> builder = new();
builder.UseInMemoryDatabase("memento");
//builder.UseSqlServer(a => { });
return builder.Options;
}
正常的解决方案是围绕需要它的工作创建一个范围。由于您的服务是周期性的,我建议为每个基于时间的调用设置一个范围。这就是我为我的预定服务所做的。
注入
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 的正常模式是为每个请求创建一个新范围。