UserManager 错误“在前一个操作完成之前在此上下文上启动了第二个操作”
Posted
技术标签:
【中文标题】UserManager 错误“在前一个操作完成之前在此上下文上启动了第二个操作”【英文标题】:UserManager error "A second operation started on this context before a previous operation completed" 【发布时间】:2020-06-05 20:57:26 【问题描述】:在我的 Blazor 服务器端应用程序中,我有多个组件,每个组件都通过依赖注入使用 UserManager,这些组件通常呈现在同一页面上。例如,我使用 NavMenu 中的 UserManager 向用户显示/隐藏某些导航项,然后在页面本身内设置逻辑以防止导航到页面本身中的相同页面。通常在导航到具有此逻辑的页面时,NavMenu 和 Page UserManager 似乎会发生冲突,从而导致错误:
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.
我确信这是其他人遇到的问题,但无法找到解决方案。如果我在包含多个带有注入 UserManager 的组件的页面上点击刷新,则最常发生这种情况。我很感激可以提供的任何帮助,如果需要,可以提供更多信息!
根据要求,这是我对 UserManager 的注册。 ApplicationUserManager 目前实际上并没有覆盖 UserManager 中的任何功能,只是为未来的定制/增强而实现:
services.AddIdentity<WS7.Engine.Models.Identity.ApplicationUser, WS7.Engine.Models.Identity.ApplicationRole>(options =>
options.SignIn.RequireConfirmedAccount = true;
options.User.RequireUniqueEmail = true;
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
)
.AddEntityFrameworkStores<WS7.Areas.Identity.Data.ApplicationIdentityContext>()
.AddUserManager<ApplicationUserManager>()
.AddSignInManager<ApplicationSignInManager>()
.AddRoles<ApplicationRole>()
.AddDefaultTokenProviders();
可能值得注意的是,似乎出现此错误的调用(基于堆栈跟踪)都在所涉及的各个组件的 OnInitializedAsync() 方法中。
两个组件的示例: 组件 1:
protected override async Task OnInitializedAsync()
await base.OnInitializedAsync();
await Authorize();
private async Task Authorize()
bool allowNavigate = (AllowedRoleIds.Count() == 0);
var contextUser = _AuthorizeHttpContextAccessor.HttpContext.User;
if (contextUser != null)
var user = await _AuthorizeUserManager.GetUserAsync(contextUser);
if (user != null)
var result = await _AuthorizeIdentityService.GetUserRightsAsync(new Engine.Models.GetUserRightsParams()
UserID = user.Id
);
if (result.Succeeded == Engine.Models.Base.SuccessState.Succeeded)
if (result.UserRightIDs.Any(uri => AllowedRoleIds.Split(",").Any(ari => ari.Equals(uri, StringComparison.CurrentCultureIgnoreCase))))
allowNavigate = true;
if (allowNavigate == false)
_AuthorizeNavigationManager.NavigateTo("/Identity/Account/Login");
组件 2:
protected override async Task OnInitializedAsync()
await RefreshData();
await base.OnInitializedAsync();
private async Task RefreshData()
var userAccountsResult = await _IdentityService.GetAspNetUserAccountsAsync(new Engine.Models.GetAspNetUserAccountsParams()
//Return all. Don't set any Params
);
if (userAccountsResult.Succeeded == SuccessState.Succeeded)
var users = await _userManager.Users.ToListAsync();
var usersView = users.Select(u => new UserViewModel()
Id = u.Id,
UserName = u.UserName,
FirstName = u.FirstName,
LastName = u.LastName,
Email = u.Email,
AccountStatus = u.ApprovedStatus,
EmailConfirmed = u.EmailConfirmed,
Active = !u.InActive,
UserAccounts = userAccountsResult.UserAccounts.Where(ua => ua.UserID == u.Id).Select(ua => new UserAccountModel()
Account = ua.Account
).ToList()
).ToList();
Users = usersView;
FilteredUsers = usersView;
else
_StatusService.SetPageStatusMessage(new PageStatusMessageEventArgs()
AlertType = AlertType.Danger,
Message = "There was an issue initializing the page."
);
一个示例异常的堆栈跟踪:
System.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. at Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection() at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.AsyncQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync() at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken) at WS7.Areas.Identity.Data.ApplicationUserManager.FindByIdAsync(String userId) in C:\VB6\Web\WS7\WS7\Areas\Identity\Data\ApplicationUserManager.cs:line 31 at WS7.Areas.Identity.Data.ApplicationUserManager.GetUserAsync(ClaimsPrincipal principal) in C:\VB6\Web\WS7\WS7\Areas\Identity\Data\ApplicationUserManager.cs:line 35 at WS7.Components.PDAuthorizeBase.Authorize() in C:\VB6\Web\WS7\WS7\Components\PDAuthorizeBase.cs:line 51 at WS7.Components.PDAuthorizeBase.OnInitializedAsync() in C:\VB6\Web\WS7\WS7\Components\PDAuthorizeBase.cs:line 35
【问题讨论】:
@HenkHolterman 我已将我的 UserManager 注册码添加到主帖中。此外,我不相信我有任何遗漏的等待或任何异步无效,但我会重新审查我的项目。我在 Visual Studio 的“错误列表”窗口中没有显示任何警告。 @HenkHolterman 我有两个碰撞组件的示例。谢谢! @HenkHolterman 另外,澄清一下,_IdentityService 对象是一项服务,它通过 WebApi 执行某些身份相邻操作 - 用户管理器无法完成的数据检索/操作(例如自定义表管理) @HenkHolterman 我在帖子末尾添加了一个堆栈跟踪。谢谢! UserManager 是 WS7 项目中唯一可访问的 DBContext;其他一切目前都通过 WebAPI 在一个单独的项目中处理。 UserManager 不总是单例吗?有没有办法以其他方式声明它?由于异步版本不接受 ClaimsPrincipal 对象,因此我对 GetUserID 或 GetUserName 非异步进行了几次调用-这些可能相关吗?我在帖子中添加了它,但这主要发生在我刷新页面并创建与服务器的新连接时。 【参考方案1】:我认为您可能会在这里找到解决问题的方法:
在这些情况下,您应该使用
OwningComponentBase<T>
。下面是一个 显示正确模式的更新示例。
Read this。 See also this...
您是否在 Server Blazor 应用程序中使用 HttpContext ?如果你这样做,你不应该, 因为 Server Blazor App 不是基于 HTTP 的应用程序,而是基于 WebSocket 的应用程序。
希望这会有所帮助...
【讨论】:
如果我理解正确,根据链接中提供的示例项目,将我的组件切换到 OwningComponentBase 并注入 UserManager 应该可以解决此问题?我尝试了这个但没有成功。另外,我目前正在通过 IHttpContextAccessor 获取 HTTPContext。使用 AuthenticationStateProvider 的方法是否正确? 抱歉,由于我现在比较忙,所以现在我无法帮助您解决主要问题。但是,我建议您更改 DBContext 的范围。以下链接是我的帖子如何在最初访问您的应用程序时访问 HttpContext,在建立 WebSocket 连接之前,这是 HttpContext 唯一可用的时间。关于您关于 AuthenticationStateProvider 的问题,答案是肯定的。您必须非常认真地学习如何使用此服务和其他相关组件。这就是 Blazor 的发展方向。 感谢 AuthenticationStateProvider 的提示!有没有办法改变 UserManager 中 DBContext 的范围?到目前为止,我试图这样做但没有成功。以上是关于UserManager 错误“在前一个操作完成之前在此上下文上启动了第二个操作”的主要内容,如果未能解决你的问题,请参考以下文章
Blazor:在前一个操作完成之前在此上下文上启动了第二个操作
Entity Framework Core:在前一个操作完成之前在此上下文上启动了第二个操作
asp.net core 在前一个操作完成之前在此上下文上启动了第二个操作
对 ITVF 的引用会引发“在前一个操作完成之前在此上下文上启动的第二个操作”异常