登录管理器<User>提供"a second operation started on this context"



在提问之前,我已经阅读了以下问题:

在上
  • 一个操作完成之前,在此上下文上启动了第二个操作
  • 如何修复"在此上下文上开始的第二个操作之前 [...]
  • 用户管理器错误 - 在此上下文上启动的第二个操作在 [...] 之前启动
  • 在上一个 [...] 之前,在此上下文上开始了第二个操作 [...]

按照回答这些问题时给出的建议,我检查了我的async呼叫是否具有其await指令,并且我验证了Startup.cs中没有将任何内容配置为static

我收到以下错误

无效操作异常:在上一个操作完成之前,在此上下文上启动了第二个操作。不保证任何实例成员都是线程安全的。

当以下代码连续调用两次时。

代码减少到理解所需的最低限度

public async Task<IActionResult> Login(LoginViewModel model)
{
/* [...] */
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, isPersistent: model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
/* [...] */
}
/* [...] */
}

登录管理器声明为private readonly SignInManager<User> _signInManager;,并通过构造函数的依赖项注入获取。

DbContext 和 Identity 上下文在下面的代码中配置为服务。据我所知,没有宣布static

services.AddDbContext<RelaxationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("RelaxationDbContext")));
services.AddIdentity<User, AppIdentityRole>()
.AddEntityFrameworkStores<RelaxationDbContext>()
.AddDefaultTokenProviders()
.AddErrorDescriber<FrenchIdentityErrorDescriber>(); 

为什么我在那里收到错误?框架中是否有错误或我做错了什么? 如何防止将来发生此错误?

导致此问题的原因是上下文无法执行第一个操作并卡住。 最常见的原因是

  1. 您正在使用异步上下文,但您的操作需要更长的时间才能完成。
  2. 连接字符串错误,因为哪个操作需要更长的时间才能完成。

事实证明,由于我无法弄清楚如何使用HasData在我的DbContext中播种测试用户,因为我没有任何散列密码的方法,我最终使用以下代码在主控制器的构造函数中生成了用户

var findByEmailAsync = _userManager.FindByEmailAsync("foo@foo.foo");
if (findByEmailAsync.Result == null)
_userManager?.CreateAsync(new User()
{
Id = "37846734-172e-4149-8cec-6f43d1eb3f60",
Email = "foo@foo.foo",
UserName = "foo@foo.foo"
}, "Password_1");

然后,由于我目前正在研究"更改电子邮件"功能,因此在更改电子邮件并确认更改后,用户尝试重新登录。见鬼,这就是恶作剧进来的地方!

由于用户更改了电子邮件,因此FindByEmailAsync方法在数据库中找不到它,从而导致调用CreateAsync。由于某种原因,此调用有时会正常运行,有时会崩溃......但大多数情况下,应用程序会在下一次调用_userManager时崩溃,这几乎总是在登录尝试期间发生。

我真的不明白为什么返回的是这个错误而不是duplicate id错误......

作为临时修复,直到我弄清楚如何在数据库中为用户播种,我已经用这个var findByEmailAsync = _userManager.FindByIdAsync("37846734-172e-4149-8cec-6f43d1eb3f60");替换了代码的第一行

相关内容

最新更新