dotnetdevcsharp
dotnetdevcsharp

Reputation: 3980

A second operation started on this context before a previous operation completed Asp.net EF Core

I have a small issue i keep getting I am using view components on a page and I keep getting the following. I am using asp.net core 3.1 and ef core 3.1

A database operation failed while processing the request. InvalidOperationException: A second operation started on this context before a previous operation completed. This is usually caused by different threads 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. There are pending model changes for MISDBContext In Visual Studio, use the Package Manager Console to scaffold a new migration for these changes and apply them to the database:

PM> Add-Migration [migration name] PM> Update-Database Alternatively, you can scaffold a new migration and apply it from a command prompt at your project directory:

dotnet ef migrations add [migration name] dotnet ef database update

I have checked on SO and it recommended that you add the following to your class now I am i right in thinking i dont need the second context at all is that what is causing the issue in my case. I added the line

ServiceLifetime.Transient

Apparently the above line allows for more concurrent connections to the context.

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

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

This is the typical layout of my view component I think in fact it may be this one that is causing the issue cause im trying to access the user store at the same time as the context.

 private Task<ApplicationUser> GetCurrentUserAsync() => _userManager.GetUserAsync(HttpContext.User);
    public async Task<Guid> GetCurrentTennantId() {
        ApplicationUser usr = await GetCurrentUserAsync();
        TempData["TeannantId"] = usr?.Id;
        Guid.TryParse(usr?.Id, out Guid resultTennantId);
        return resultTennantId;
    }
    private Task<List<ApplicationUser>> GetItemsAsync() {
        string currentUser =  GetCurrentTennantId().Result.ToString();
        var excludeCurrentUser= _userManager.Users.Where(w => w.Id != currentUser).ToListAsync();
        return excludeCurrentUser;
    }
}

Upvotes: 0

Views: 745

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456457

Apparently the above line allows for more concurrent connections to the context.

No; it creates a new context for each request. Each context can only be used for one operation at a time. So, e.g., if your context was previously a singleton, then only one HTTP request could make an operation at a time.

I think in fact it may be this one that is causing the issue cause im trying to access the user store at the same time as the context.

This code by itself can't cause the problem, but if this pattern is repeated in your code base, then it could cause the problem.

In summary, use async and await for all Task<T>-returning methods, unless the method is trivial. E.g., GetCurrentUserAsync is trivial (it's just passing through to another method), so it's fine to elide async and await there. GetItemsAsync is definitely not trivial, so it should be using async and await:

private async Task<List<ApplicationUser>> GetItemsAsync() {
  string currentUser = (await GetCurrentTennantId()).ToString();
  return await _userManager.Users.Where(w => w.Id != currentUser).ToListAsync();
}

If you apply async and await in a similar manner across your codebase, you should resolve the concurrent context issue.

Upvotes: 1

Related Questions