Blazor QuickGrid调用SetCurrentPageIndexAsync时DbContext并发异常求助
Blazor QuickGrid + Identity 用户数据分页/过滤时DbContext并发异常解决方案
问题核心
UserManager.Users返回的查询依赖Identity注入的作用域DbContext实例,当QuickGrid分页、过滤触发多次异步查询时,同一个DbContext会被并发调用,导致"A second operation was started on this context instance"异常。你配置的DbContextFactory未生效,是因为UserManager默认不会使用工厂创建的临时DbContext实例。
解决方案
1. 用DbContextFactory替代直接使用UserManager.Users
在组件中注入IDbContextFactory<IdentityContext>,每次查询用户数据时创建新的DbContext实例,确保每次查询使用独立上下文,避免并发冲突。
修改组件代码:
@inject IDbContextFactory<IdentityContext> IdentityContextFactory @inject UserManager<AppUser> userManager @code { PaginationState pagination = new PaginationState { ItemsPerPage = 10 }; string nameFilter; int minMedals; int maxMedals = 20; GridSort<AppUser> sortByBool = GridSort<AppUser> .ByAscending(p => p.IsApproved) .ThenDescending(p => p.LastLoginDate); protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); // 确保在Blazor同步上下文内触发状态更新 pagination.TotalItemCountChanged += (sender, eventArgs) => InvokeAsync(StateHasChanged()); } // 每次获取查询时创建新的DbContext private IQueryable<AppUser> GetUsersQueryable() { var context = IdentityContextFactory.CreateDbContext(); return context.Users.AsQueryable(); } private IQueryable<AppUser> FilteredCountries { get { var result = GetUsersQueryable().Where(c => c.AccessFailedCount <= maxMedals); if (!string.IsNullOrEmpty(nameFilter)) { result = result.Where(c => c.UserName.Contains(nameFilter)); } if (minMedals > 0) { result = result.Where(c => c.AccessFailedCount >= minMedals); } return result; } } private async Task GoToPageAsync(int pageIndex) { await pagination.SetCurrentPageIndexAsync(pageIndex); } private string? PageButtonClass(int pageIndex) => pagination.CurrentPageIndex == pageIndex ? "current" : null; private string? AriaCurrentValue(int pageIndex) => pagination.CurrentPageIndex == pageIndex ? "page" : null; }
2. 优化Identity服务配置(可选)
确保Identity服务绑定到DbContextFactory对应的上下文,在Program.cs/Startup.cs中确认配置:
services.AddDbContextFactory<IdentityContext>(options => options.UseSqlServer(identityConnectionString), ServiceLifetime.Transient); services.AddDefaultIdentity<AppUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<IdentityContext>();
3. 避免不必要的状态更新
TotalItemCountChanged事件中使用InvokeAsync(StateHasChanged()),确保状态更新在Blazor同步上下文执行,避免重复渲染触发额外查询。
原配置失效原因
你配置了DbContextFactory,但UserManager.Users内部使用的是注入的作用域DbContext实例,而非工厂创建的临时实例。当组件多次触发查询时,同一个作用域内的DbContext被复用,导致并发操作冲突。
内容的提问来源于stack exchange,提问作者mz1378
相关产品推荐
相关产品推荐

