【发布时间】:2020-05-02 00:25:21
【问题描述】:
我的目标
我想创建一个新的 IdentityUser 并显示已通过同一 Blazor 页面创建的所有用户。此页面有:
- 通过您的表单将创建一个 IdentityUser
- 第三方的网格组件 (DevExpress Blazor DxDataGrid),显示所有使用 UserManager.Users 属性的用户。该组件接受 IQueryable 作为数据源。
问题
当我通过表单(1)创建新用户时,会出现以下并发错误:
InvalidOperationException:在前一个操作完成之前在此上下文上启动了第二个操作。不保证任何实例成员都是线程安全的。
我认为问题与 CreateAsync(IdentityUser user) 和 UserManager.Users 指的是同一个 DbContext
的事实有关这个问题与第三方组件无关,因为我用一个简单的列表替换了同样的问题。
重现问题的步骤
- 使用身份验证创建新的 Blazor 服务器端项目
-
使用以下代码更改 Index.razor:
@page "/" <h1>Hello, world!</h1> number of users: @Users.Count() <button @onclick="@(async () => await Add())">click me</button> <ul> @foreach(var user in Users) { <li>@user.UserName</li> } </ul> @code { [Inject] UserManager<IdentityUser> UserManager { get; set; } IQueryable<IdentityUser> Users; protected override void OnInitialized() { Users = UserManager.Users; } public async Task Add() { await UserManager.CreateAsync(new IdentityUser { UserName = $"test_{Guid.NewGuid().ToString()}" }); } }
我注意到了什么
- 如果我将实体框架提供程序从 SqlServer 更改为 Sqlite,则该错误将永远不会显示。
系统信息
- ASP.NET Core 3.1.0 Blazor 服务器端
- Entity Framework Core 3.1.0 基于 SqlServer 提供者
我已经看到的
- Blazor A second operation started on this context before a previous operation completed:建议的解决方案对我不起作用,因为即使我将 DbContext 范围从 Scoped 更改为 Transient 我仍然使用相同的 UserManager 实例及其包含DbContext 的同一个实例
- StackOverflow 上的其他人建议为每个请求创建一个新的 DbContext 实例。我不喜欢这个解决方案,因为它违反了依赖注入原则。无论如何,我无法应用此解决方案,因为 DbContext 包装在 UserManager 中
- Create a generator of DbContext:这个解决方案和上一个很像。
- Using Entity Framework Core with Blazor
我为什么要使用 IQueryable
我想传递一个 IQueryable 作为我的第三方组件的数据源,因为它可以将分页和过滤直接应用于查询。此外,IQueryable 对 CUD 很敏感 操作。
【问题讨论】:
-
你可以调试一下,看看哪条线启动了两次。可能是 Add 方法?
-
不幸的是,我无法捕获 Visual Studio 调用堆栈窗口输出,因为当我单击“单击我”按钮时,Visual Studio 将崩溃并报告我在帖子中写的异常。无论如何,我创建了一个小项目,您可以克隆并尝试它。请记住在 Startup.cs 文件 github.com/Blackleones/BlazorProblemReleatedTo18340 中更改第 35 行
-
对我来说它不会崩溃并且尝试 catch 在 Add 方法中显示以下异常:
Invalid attempt to call ReadAsync when reader is closed.可能 CreateAsync 与 ReadAsync 冲突? -
谢谢。我尝试通过终端运行示例,但遇到了与您之前提到的相同的异常。无论如何,你可以看到 CreateAsync 是来自 Identity Framework 的 UserManager 服务的一种方法,所以我不知道如何在不重写另一个 UserManager 的情况下解决这个问题。
-
我没有使用 MARS
标签: asp.net-core entity-framework-core blazor blazor-server-side