简体   繁体   中英

Async method: Second operation was started on this context before a previous operation completed

I'm new to Blazor and don't have much experience working with Tasks, so hopefully I'm just making a foolish mistake. I have an async method that is called via button press, but if the method is called again within 1-2 seconds I get the following exception.

Error: System.InvalidOperationException: A second operation was started on this context before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.

This button is rendered for each row in a Users table. I'm trying to delete multiple user records in quick succession, but receive the above error.

Here is the code for the button press (using AntBlazor)

 <Button Type="primary" Danger OnClick="@(async() => await RemoveAsync(user))">Remove User</Button>

And here is the code for the RemoveAsync method.

private async Task RemoveAsync(User user)
{
   await UserService.UpdateUserAsync(user);
}

Am I misunderstanding how async/await works? or do I need to make use of Tasks to ensure the action is complete?

Edit:

Heres the UserService.UpdateUserAsync() code

public async Task<bool> UpdateUserAsync(User user)
{
   _appDBContext.Users.Update(user);
   await _appDBContext.SaveChangesAsync();
   return true;
}

Your code

public async Task<bool> UpdateUserAsync(User user)
{
   _appDBContext.Users.Update(user);
   await _appDBContext.SaveChangesAsync();
   return true;
}

I assume that _appDBContext is injected in the constructor, and that UserService itself is registered as Scoped.

That means that a single _appDBContext lives for the duration of your Form, accumulating tracking data. And because of async it runs the risk of being re-entered which is your direct problem.

One solution is not to inject a DbContext but a DbContextFactory .

And then it looks like:

public async Task<bool> UpdateUserAsync(User user)
{
   using var dbContext = _dbContextFactory.CreateDbContext(); 
   dBContext.Users.Update(user);
   var n = await dBContext.SaveChangesAsync();
   return n == 1; // just for being accurate
}

Now the context is scoped to each method. Much lighter on memory and you can have many overlapping operations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM