众所周知,官方推荐用法是通过AddDbContextPool注册DbContext服务(默认为Scoped),然后再依赖注入到各个地方。但是实际上,这个用法有一个非常大的问题:即便通过await,也无法防止Blazor Server重入同一个db实例,造成报错。根据网上的资料,了解到在Blazor Server中AddDbContextPool实际上根本无法在同一个Scoped范围中创建多个db实例,也就是跟AddDbContext的用法几乎无差别。于是就有了更为推荐的配置:使用AddDbContextFactory来绑定工厂模式的dbcontext。
工厂模式很简单粗暴,其实跟直接new一个几乎没有差别,最主要的区别就是工厂模式能帮你直接把配置都填好,基本上就是这样了。由于dbcontext是一个占用了系统/其他软件资源的东西,于是需要在调用完成后释放,那么这里推荐就是用using在某一个作用域中使用后自动释放。大致的代码如下:
首先是注册factory:
builder.Services.AddDbContextFactory<ContactContext>(opt =>
opt.UseSqlServer(...));
在需要注入和使用的地方:
public TestService2(AddDbContextFactory<ContactContext> factory)
{
_factory = factory;
}
public virtual async Task<NewProgramViewModel> HandleAsync()
{
using var context=_factory.CreateContext())
{
...
}
}
就是如此简单粗暴,并不复杂,但是也是一个刚入门会遇到的坑,非常建议收藏一波。
对了,如果要在组件里面使用,可以用如下的方式:
@implements IDisposable
@inject IDbContextFactory<ContactContext> DbFactory
...
@code
{
ContactContext? Context;
public void Dispose()
{
Context?.Dispose();
}
protected override async Task OnInitializedAsync()
{
Context = DbFactory.CreateDbContext();
...
}
}