В моем приложении Blazor на стороне сервера у меня есть несколько компонентов, каждый из которых использует UserManager посредством внедрения зависимостей, которые часто отображаются на одной странице. Например, я использую UserManager в NavMenu, чтобы показать / скрыть определенные элементы навигации от пользователя, а затем добавить логики c на самих страницах, чтобы предотвратить переход к тем же страницам на самих страницах. Часто при переходе на страницу, имеющую этот лог c, NavMenu и Page UserManager Page сталкиваются, что приводит к ошибке:
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.
Я уверен, что это проблема, с которой столкнулись другие , но не смогли найти решение. Чаще всего это происходит, если я нажимаю Refre sh на странице, содержащей несколько компонентов, с введенным 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();
Возможно, стоит отметить, что вызовы, которые кажутся раздувающимися с этой ошибкой (на основе трассировки стека) ) оба входят в методы OnInitializedAsyn c () различных задействованных компонентов.
Пример двух компонентов: Компонент 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