Blazor等待ef核心完成请求



所以现在我得到了

Error: System.InvalidOperationException: A second operation was started on this context before a previous operation completed.

因为blazor似乎不尊重当前的请求。

我正在做的事情是这样的:

FirstComponent.razor

@inject IService _service; // abstracted service that calls EF
<layout> // layout stuff here
<SecondComponent /> // second blazor component
</layout>
@code {
protected override async Task OnInitializeAsync()
{
var getSomething = await _service.OnInitializedAsync();
}
}

SecondComponent.razor

@inject IService _service; // abstracted service that calls EF
@code {
protected override async Task OnInitializedAsync()
{
var getSomething = await _service.GetSomething();
}
}

所以我把我的实体分成多个子组件来编辑它;"父";调用所有这些子组件的组件。


编辑1

我的IService应该是这样的。

public interface IService
{
public Task<Something> GetSomething();
}
internal class Service : IService
{
private readonly SomethingRepository _repo;
public Service(SomethingRepository repo)
{
_repo = repo;
}
public async Task<Something> GetSomething() => _repo.GetAsync();
}
internal SomethingRepository
{
private readonly AppDbContext _context;
public SomethingRepository(AppDbContext context)
{
_context = context;
}
public async Task<Something> GetAsync() => ...;//implementation of whatever
}

我正在使用AddDbContext将我的AppDbContext添加到服务集合,并使用AddScoped将我的服务和存储库添加到

对于Blazor Server应用程序,您不应该使用DbContext的现有DI生存期。相反,为每个请求创建一个新的请求,或者将其扩展到一个组件。根据:

EF Core为ASP.NET Core应用程序提供AddDbContext扩展默认情况下,将上下文注册为作用域服务。在Blazor服务器中应用程序,作用域服务注册可能会出现问题,因为实例在用户电路内的组件之间共享。DbContext不是线程安全的,也不是为并发使用而设计的。这个由于以下原因,现有的使用寿命是不合适的:

  • Singleton在应用程序的所有用户中共享状态,并导致不适当的同时使用
  • Scoped(默认设置(在同一用户的组件之间提出了类似的问题
  • 瞬态结果为每个请求生成一个新实例;但是,由于组件可以是长寿命的,这会导致比实际情况更长的环境寿命预期

以下建议旨在提供一致的在Blazor Server应用程序中使用EF Core的方法。

  • 默认情况下,考虑每个操作使用一个上下文
  • 使用标志来阻止多个并发操作:
  • 对于利用EF Core的更改跟踪或并发控制的长寿命操作,请将上下文范围扩展到组件

带有实体框架核心(EFCore(的ASP.NET Core Blazor服务器

通常,当您在调用服务时使用async/await,但不使用标志来停止子组件的呈现时,就会发生这种情况。这应该可以解决您的大部分";第二个操作已启动"问题。

<layout>
@if(_loading)
{
<span> Loading .... </span>
}
else{
<ChildComponent/>
}
</layout>

@code
{
bool _loading;
protected override async Task OnInitializedAsync(){
_loading = true;
var data = _service.getSomething();
_loading = false;
}
}

将其添加到连接字符串中"MultipleActiveResultSets=true";

因此,使用Henk Holterman提供的工厂模式对我来说不是一个解决方案。请参阅:https://learn.microsoft.com/en-us/ef/core/dbcontext-configuration/#using-a-dbcontext-factor-eg-for-blazor

所做的工作正在改变从ScopedTransient的所有生命周期。包括数据库上下文。

services.AddDbContext<AppDbContext>(..options.., ServiceLifetime.Transient);
services.AddTransient<IService, Service>();
services.AddTransient<SomethingRepository>();

最新更新