Leo*_*rci 10 entity-framework-core asp.net-core blazor blazor-server-side
我的目标
我想创建一个新的 IdentityUser 并显示已通过同一个 Blazor 页面创建的所有用户。该页面有:
问题
当我通过表单 (1) 创建一个新用户时,我会收到以下并发错误:
InvalidOperationException:在上一个操作完成之前,在此上下文中启动了第二个操作。不保证任何实例成员都是线程安全的。
我认为问题与CreateAsync(IdentityUser user)和UserManager.Users指的是相同的 DbContext 的事实有关
该问题与第三方的组件无关,因为我重现了相同的问题,并用一个简单的列表替换了它。
重现问题的步骤
使用以下代码更改 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()}" });
}
}
Run Code Online (Sandbox Code Playgroud)我注意到的
系统信息
我已经看到的
为什么我要使用 IQueryable
我想传递一个 IQueryable 作为我第三方组件的数据源,因为它可以直接对查询应用分页和过滤。此外,IQueryable 对 CUD 操作很敏感。
Leo*_*rci 10
更新(08/19/2020)
您可以在此处找到有关如何同时使用 Blazor 和 EFCore的文档
更新(07/22/2020)
EFCore 团队在 Entity Framework Core .NET 5 Preview 7 中引入了 DbContextFactory
[...]这种解耦对于 Blazor 应用程序非常有用,推荐使用 IDbContextFactory,但在其他场景中也可能有用。
如果您有兴趣,可以在宣布 Entity Framework Core EF Core 5.0 Preview 7 中阅读更多内容
更新(07/06/2020)
微软发布了一个关于 Blazor(两种模型)和 Entity Framework Core 的有趣视频。请看19:20,他们在讨论如何用EFCore管理并发问题
我向 Daniel Roth BlazorDeskShow - 2:24:20询问了这个问题,它似乎是设计上的 Blazor服务器端问题。DbContext 默认生命周期设置为Scoped. 因此,如果您在同一页面中至少有两个组件尝试执行异步查询,那么我们将遇到异常:
InvalidOperationException:在上一个操作完成之前,在此上下文中启动了第二个操作。不保证任何实例成员都是线程安全的。
这个问题有两种解决方法:
services.AddDbContext<ApplicationDbContext>(opt =>
opt.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")), ServiceLifetime.Transient);
Run Code Online (Sandbox Code Playgroud)
DbContext.无论如何,每个解决方案都有效,因为它们创建了DbContext.
我的问题DbContext与UserManager<TUser>它没有严格的关系,但与它有Scoped终生的关系。将 DbContext 的生命周期设置为Transient并没有解决我的问题,因为 ASP.NET CoreUserManager<TUser>在我第一次打开会话时创建了一个新实例,并且它一直存在,直到我没有关闭它。这UserManager<TUser>是在同一页面上的两个组件内。然后我们遇到了之前描述的相同问题:
UserManager<TUser>实例的两个组件,其中包含一个瞬态DbContext。目前,我用另一种解决方法解决了这个问题:
UserManager<TUser>直接使用,而是通过它创建了一个新实例,IServiceProvider然后它就可以工作了。我仍在寻找一种方法来更改 UserManager 的生命周期而不是使用IServiceProvider.提示:注意服务的生命周期
这是我学到的。我不知道这一切是否正确。
| 归档时间: |
|
| 查看次数: |
3166 次 |
| 最近记录: |