ASP.Net 使用 FindByIdAsync 时取消了核心标识
ASP.Net Core Identity canceled when using FindByIdAsync
我有一个使用 Asp.Net Core Identity 框架和 EF Core 的小项目。
一个函数调用 UserManager.FindByIdAsync(id) 并且它 returns 是正确的对象。但是,它仅在应用程序启动后几分钟起作用。只要服务器繁忙,它就可以正常工作,但只要应用程序空闲超过 1-2 分钟,请求就会失败。
它失败了:
*OperationCanceledException: The operation was canceled.
System.Threading.CancellationToken.ThrowOperationCanceledException()*
堆栈跟踪看起来像这样:
*System.Threading.CancellationToken.ThrowOperationCanceledException()
Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore.FindByIdAsync(string userId, CancellationToken cancellationToken)
Microsoft.AspNetCore.Identity.UserManager.FindByIdAsync(string userId)
MyProject.Areas.Admin.ControllerServices.UserService+<GetUser>d__11.MoveNext() in UserService.cs*
我仍然登录,因为其他页面工作正常。
对 EF context.Users.FindAsync(new object[] { id })
的简单调用将按预期工作,但包含 FindByIdAsync
的下一行将失败。
这一切在开发环境中完美运行,当应用程序安装在服务器 运行 WS 2008 R2 上的 IIS 时会出现错误。回收应用程序池将使其重新工作,直到它再次空闲几分钟。
我注意到当像 'Connection id "0HL5E91K33IIQ" reset.' 这样的行被记录时,应用程序开始失败。在此之前它有效。
FindByIdAsync 不是唯一失败的身份函数,许多其他函数失败并出现相同的错误。
我错过了什么?
我会回答我自己的问题,希望这对以后的其他人有所帮助。
对我来说,这一切都归结为注入服务的生命周期。
UserManager
依赖于 IHttpContextAccessor
(这是 CancellationToken
的来源)并且当生命周期不匹配时它的行为不正确。
IHttpContextAccessor
作为单例服务添加,而 UserManager
作为作用域服务添加。我使用 UserManager
的服务被添加为单例服务。
将其更改为 Scoped 会使错误消失。
在我的案例中,它归结为完全相同的问题,但是由 ASP.Net Core 的 DI 实现中的一个非常微妙的设计 "flaw" 引起的。出于各种原因,我更喜欢使用 SimpleInjector,但与为容器内构建提供的良好扩展方法相比,将 ASP.Net Identity Core 填充到其中很难。所以我把框架的东西放在框架容器里,我的业务东西放在 SimpleInjector 里,决定 "Authentication and Authorization" 被认为是 "framework"。只有 AccountController 由框架容器使用交叉连接解析。但是,在请求范围之外使用 app.ApplicationServices.GetService<AccountController>()
不会失败,但是 returns 一个 Singleton 会存活下来!不幸的是,当您让 SimpleInjector 验证其配置时,就会发生这种情况。导致故障(错误登录)的第一个请求会使您的整个运行时留下一个有缺陷的单例实例。解决方案在 SimpleInjectors 文档中有详细记录,请改用它们的扩展名 app.GetRequiredRequestService<AccountController>()
。
更新asp.net核心2.0
现在,你不会得到可疑的单例实例,而是一个异常:
System.InvalidOperationException: 'Cannot resolve scoped service 'WebApplication15.Controllers.AccountController' from root provider.'
我有一个使用 Asp.Net Core Identity 框架和 EF Core 的小项目。 一个函数调用 UserManager.FindByIdAsync(id) 并且它 returns 是正确的对象。但是,它仅在应用程序启动后几分钟起作用。只要服务器繁忙,它就可以正常工作,但只要应用程序空闲超过 1-2 分钟,请求就会失败。
它失败了:
*OperationCanceledException: The operation was canceled.
System.Threading.CancellationToken.ThrowOperationCanceledException()*
堆栈跟踪看起来像这样:
*System.Threading.CancellationToken.ThrowOperationCanceledException()
Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore.FindByIdAsync(string userId, CancellationToken cancellationToken)
Microsoft.AspNetCore.Identity.UserManager.FindByIdAsync(string userId)
MyProject.Areas.Admin.ControllerServices.UserService+<GetUser>d__11.MoveNext() in UserService.cs*
我仍然登录,因为其他页面工作正常。
对 EF context.Users.FindAsync(new object[] { id })
的简单调用将按预期工作,但包含 FindByIdAsync
的下一行将失败。
这一切在开发环境中完美运行,当应用程序安装在服务器 运行 WS 2008 R2 上的 IIS 时会出现错误。回收应用程序池将使其重新工作,直到它再次空闲几分钟。
我注意到当像 'Connection id "0HL5E91K33IIQ" reset.' 这样的行被记录时,应用程序开始失败。在此之前它有效。
FindByIdAsync 不是唯一失败的身份函数,许多其他函数失败并出现相同的错误。
我错过了什么?
我会回答我自己的问题,希望这对以后的其他人有所帮助。
对我来说,这一切都归结为注入服务的生命周期。
UserManager
依赖于 IHttpContextAccessor
(这是 CancellationToken
的来源)并且当生命周期不匹配时它的行为不正确。
IHttpContextAccessor
作为单例服务添加,而 UserManager
作为作用域服务添加。我使用 UserManager
的服务被添加为单例服务。
将其更改为 Scoped 会使错误消失。
在我的案例中,它归结为完全相同的问题,但是由 ASP.Net Core 的 DI 实现中的一个非常微妙的设计 "flaw" 引起的。出于各种原因,我更喜欢使用 SimpleInjector,但与为容器内构建提供的良好扩展方法相比,将 ASP.Net Identity Core 填充到其中很难。所以我把框架的东西放在框架容器里,我的业务东西放在 SimpleInjector 里,决定 "Authentication and Authorization" 被认为是 "framework"。只有 AccountController 由框架容器使用交叉连接解析。但是,在请求范围之外使用 app.ApplicationServices.GetService<AccountController>()
不会失败,但是 returns 一个 Singleton 会存活下来!不幸的是,当您让 SimpleInjector 验证其配置时,就会发生这种情况。导致故障(错误登录)的第一个请求会使您的整个运行时留下一个有缺陷的单例实例。解决方案在 SimpleInjectors 文档中有详细记录,请改用它们的扩展名 app.GetRequiredRequestService<AccountController>()
。
更新asp.net核心2.0
现在,你不会得到可疑的单例实例,而是一个异常:
System.InvalidOperationException: 'Cannot resolve scoped service 'WebApplication15.Controllers.AccountController' from root provider.'