You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 15:39:55