我有一个小项目,它使用Asp.Net核心身份框架和EF Core。 一个函数调用UserManager.FindByIdAsync(id)并返回正确的对象。但是,它仅在应用程序启动后的几分钟内工作。只要服务器忙,它就能正常工作,但只要应用程序空闲超过1-2分钟,请求就会失败。
失败了:
*OperationCanceledException: The operation was canceled.
System.Threading.CancellationToken.ThrowOperationCanceledException()*
stacktrace看起来像这样:
*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“重置”时。正在记录,然后应用程序开始失败。在此之前它有效。
FindByIdAsync不是唯一失败的身份函数,许多其他函数失败并出现相同的错误。
我错过了什么?
答案 0 :(得分:7)
我将回答我自己的问题,希望这将有助于其他人。
对我来说,这一切都归结为注入服务的生命周期。
UserManager
取决于IHttpContextAccessor
(这是CancellationToken
来自的地方),并且在生命周期不匹配时行为不正确。
IHttpContextAccessor
被添加为Singleton服务,而UserManager
被添加为范围服务。我使用UserManager
的服务已添加为Singleton服务。
将此更改为Scoped会使错误消失。
答案 1 :(得分:0)
在我的情况下,它归结为完全相同的问题,但是由ASP.Net Core的DI实现中的一个非常微妙的设计“缺陷”引起。由于各种原因,我更喜欢使用SimpleInjector,但是将ASP.Net Identity Core填充到其中是很困难的,相比之下,为容器中的构建提供了很好的扩展方法。所以我将框架内容放在框架容器中,并将我的业务放在SimpleInjector中,决定“身份验证和授权”被认为是“框架”。框架容器仅使用交叉布线解析AccountController。但是,在请求范围外使用app.ApplicationServices.GetService<AccountController>()
不会失败,但会返回一个能够存活的 Singleton !不幸的是,当您让SimpleInjector验证它的配置时,会发生这种情况。导致故障的第一个请求(错误登录)会使整个运行时出现缺陷单例实例。 SimpleInjectors文档中详细记录了此解决方案,而是使用其扩展名app.GetRequiredRequestService<AccountController>()
。
现在,你不会得到可疑的单例实例,但是例外:
System.InvalidOperationException: 'Cannot resolve scoped service 'WebApplication15.Controllers.AccountController' from root provider.'