繁体   English   中英

在前一个操作完成之前,在此上下文上启动了第二个操作 Asp.net EF Core

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

我有一个小问题,我一直在使用页面上的视图组件,并且不断收到以下内容。 我正在使用 asp.net 核心 3.1 和 ef 核心 3.1

处理请求时数据库操作失败。 InvalidOperationException:在前一个操作完成之前在此上下文上启动了第二个操作。 这通常是由使用相同 DbContext 实例的不同线程引起的。 有关如何避免 DbContext 线程问题的详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2097913 MISDBContext 有待处理的 model 更改在 Visual Studio 中,使用 Package 管理器控制台为这些更改构建新迁移并将它们应用到数据库:

PM> Add-Migration [migration name] PM> Update-Database 或者,您可以构建一个新的迁移并从项目目录的命令提示符应用它:

dotnet ef 迁移添加 [迁移名称] dotnet ef 数据库更新

我已经检查了 SO,它建议您将以下内容添加到您的 class 现在我认为我根本不需要第二个上下文是什么导致了我的问题。 我添加了行

ServiceLifetime.Transient

显然,上面的行允许更多的并发连接到上下文。

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

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

这是我的视图组件的典型布局,我认为实际上它可能是导致问题的原因,因为我试图与上下文同时访问用户存储。

 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;
    }
}

显然,上面的行允许更多的并发连接到上下文。

不; 它为每个请求创建一个新的上下文。 每个上下文一次只能用于一个操作。 因此,例如,如果您的上下文以前是 singleton,那么一次只有一个 HTTP 请求可以进行操作。

我认为实际上这可能是导致问题的原因,因为我试图与上下文同时访问用户存储。

此代码本身不会导致问题,但如果此模式在您的代码库中重复出现,则可能会导致问题。

总之,对所有返回Task<T>的方法使用asyncawait ,除非该方法是 trivial 例如, GetCurrentUserAsync是微不足道的(它只是传递给另一个方法),所以可以省略async并在那里await GetItemsAsync绝对不是微不足道的,所以它应该使用asyncawait

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

如果您在代码库中以类似的方式应用asyncawait ,您应该解决并发上下文问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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