我在 Startup.cs 中有以下内容:
services.AddDbContext<MyDbContext>(options => options.UseSqlite(Configuration.GetConnectionString("Sqlite")));
现在,我想启动一个具有短暂生命周期的
MyDbContext
实例。这样做的原因是因为我在启动时填充缓存。那么我怎样才能获得一个由我负责处置自己的 MyDbContext
实例呢?我手头有一个IServiceProvider
。
serviceProvider.GetRequiredService<MyDbContext>();
抛出一个异常,表明它超出了范围。
我理解为什么抛出异常,但我不确定解决它的最佳方法是什么。
您需要手动创建一个范围,如下所示:
using (var scope = serviceProvider.CreateScope())
{
var scopedServices = scope.ServiceProvider;
scopedServices.GetRequiredService<MyDbContext>();
...
}
这将提供一个作用域 dbcontext,当您使用完它时,作用域闭包将自动处理它。在 Web 请求期间,每个请求都会自动创建一个范围,因此它会在请求结束时被释放。
joe-audette 的回答。 它依赖于
serviceProvider
,我不确定它来自哪里。同样在创建范围后,它会执行以下操作:
var scopedServices = scope.ServiceProvider;
...看起来它正在检索一个...ServiceProvider,这...是它开始的东西。? 这些都不清楚。
如果我正在使用 aspnet core 编写一个 Minimal API 应用程序,则没有环境
serviceProvider
对象。有一个 WebAppBuilder,从构建器中我可以获得一个类型为 WebApplication 的应用程序。
鉴于此,这对我有用。 (.NET 核心 8.0)
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
...
var app = builder.Build();
...add all my methods here...
// initialize the in-memory DB just to start out
using (var scope = app.Services.CreateScope())
{
var serviceProvider = scope.ServiceProvider;
using (var db = new TodoDb(serviceProvider.GetRequiredService<DbContextOptions<TodoDb>>())) {
var todo = new Todo("go grocery shopping");
db.Todos.Add(todo);
db.SaveChanges();
}
}
// start listening
var port = Environment.GetEnvironmentVariable("PORT") ?? "8080";
var url = $"http://0.0.0.0:{port}";
app.Run(url);
这篇文章给了我关键的提示,创建一个范围并从范围中获取服务提供商。
我不得不说,这个话题有点难以理解。我发现的大多数提示都是部分的、迟钝的、部分错误的或过时的。