EF 错误:在前一个异步操作完成之前在此上下文上启动了第二个操作

Posted

技术标签:

【中文标题】EF 错误:在前一个异步操作完成之前在此上下文上启动了第二个操作【英文标题】:EF error: A second operation started on this context before a previous asynchronous operation completed 【发布时间】:2021-05-04 09:03:32 【问题描述】:

我是 Blazor 新手,在服务器端 Blazor 应用程序 (.NET 5) 中工作,具有以下特点:

我有以下表格:

 <EditForm Model="@MyObject" OnValidSubmit="Submit">
      <DataAnnotationsValidator />
      <ValidationSummary />

     <InputText id="name" @bind-Value="MyObject.Name" />

     <button type="submit">Submit</button>
</EditForm>

后面的代码:

public MyObject MyObject  get; set;  = new MyObject();
    
[Inject]
private IMyObjectService myObjectService  get; set; 

[Inject]
private NavigationManager navigationManager  get; set; 

void Submit()

    var created = myObjectService.CreateMyObject(MyObject);

    if (created != null)
    
        navigationManager.NavigateTo("myobjects/manage");
     else
    
        // do something
    

回购:

private readonly ApplicationDbContext _dbContext;

public MyObjectRepo(ApplicationDbContext dbContext)

   _dbContext = dbContext;


public async Task<MyObject> CreateMyObject(MyObject MyObject)

   _dbContext.Add(MyObject);
   await _dbContext.SaveChangesAsync();
   return MyObject;


public async Task<bool> DoesMyObjectExistByName(string name)

    var exists = await _dbContext.MyObjects.AnyAsync(x => x.Name == name);

    if (exists) return true;
    return false;

然后我有一个MyObjectService

private readonly IMyObjectRepo _myObjectRepo ;
        
public MyObjectService(IMyObjectRepo myObjectRepo  )

    _myObjectRepo  = myObjectRepo;


public async Task<MyObject> CreateMyObject(MyObject MyObject)

   if (MyObject == null) throw new ArgumentNullException("MyObject cannot be null.");

   // THIS LINE THROWS THE EF ERROR
   var exists = await _myObjectRepo.DoesMyObjectExistByName(MyObject.Name);

   if (!exists)
   
      return await _myObjectRepo.CreateMyObject(MyObject);
    else
   
      return null;
   

但是每次调用服务创建MyObject方法,EF都会抛出错误:

错误:System.InvalidOperationException:第二个操作是 在上一个操作完成之前在此上下文中开始。这是 通常是由不同的线程同时使用相同的 DbContext 的实例。

在 Startup.cs (.NET 5) 中,我配置了瞬态生命周期。

services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("Default")),
        ServiceLifetime.Transient);

services.AddAutoMapper(typeof(Startup));
services.AddScoped<IMyObjectRepo, MyObjectRepo>();
services.AddScoped<IMyObjectService, MyObjectService>();

我认为我正在使用所有正确的语法来实现异步/等待和线程安全,有什么想法吗?

【问题讨论】:

请同时包含您的 Razor pages 或 Controler 代码(如果您使用的是 asp.net core mvc) 您的服务和存储库的生命周期是多少? 能否分享一下控制器的操作方法,以及您是如何注册MyObjectService' and MyObjectRepo`的? 更新原帖 【参考方案1】:

我自己不熟悉Blazor,但我认为您的Submit 方法应该是这样的-

async void Submit()

    var created = await myObjectService.CreateMyObject(MyObject);

    if (created != null)
    
        navigationManager.NavigateTo("myobjects/manage");
     else
    
        // do something
    

基本上,您缺少 async/await 关键字。

【讨论】:

以上是关于EF 错误:在前一个异步操作完成之前在此上下文上启动了第二个操作的主要内容,如果未能解决你的问题,请参考以下文章

在前一个异步操作完成之前,在此上下文上启动了第二个操作。使用“等待”来确保

UserManager 错误“在前一个操作完成之前在此上下文上启动了第二个操作”

使用依赖注入时,如何修复“在前一个操作完成之前在此上下文中启动的第二个操作......”?

C# EF6 使用 Unity 对一个上下文进行多次异步调用 - Asp.Net Web Api

在此上下文中启动了第二个操作

Blazor:在前一个操作完成之前在此上下文上启动了第二个操作