UserManager 错误 - 在前一个异步操作完成之前在此上下文上启动了第二个操作

Posted

技术标签:

【中文标题】UserManager 错误 - 在前一个异步操作完成之前在此上下文上启动了第二个操作【英文标题】:UserManager Error - A second operation started on this context before a previous asynchronous operation completed 【发布时间】:2014-12-08 17:19:45 【问题描述】:

我在使用 Identity v2.0.0.0、EF 6、Castle Windsor IOC Container、Microsoft SQL Server 2005 的 asp.net MVC5 Web 应用程序中遇到了这个问题

我正在尝试使用 UserManagerExtensions,FindById() 方法获取当前登录的用户,但它抛出错误“System.NotSupportedException:在前一个异步操作完成之前在此上下文上启动了第二个操作。使用“等待”以确保在调用此上下文中的另一个方法之前已完成任何异步操作。不保证任何实例成员都是线程安全的"

我从堆栈跟踪中了解到是“AsyncHelper.RunSync()”导致问题,我没有在我的代码中使用任何异步函数,而是使用 AsyncHelper 的“FindById()” 参考 -: http://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.Core/2.0.0-beta1-140129/Release/Default/Microsoft.AspNet.Identity.Core/Microsoft.AspNet.Identity.Core/Extensions/UserManagerExtensions.cs?ImageName=Microsoft.AspNet.Identity.Core

关于这个身份错误的信息似乎很少,我在我的应用程序的不同部分使用当前登录用户的详细信息,当调用我的服务层中的 GetCurrentLoggedInUser() 函数时,这个错误似乎随机发生。请帮忙....

我的代码和堆栈跟踪如下---- 注意:我在这里发现了另一个类似类型的事件:https://aspnetidentity.codeplex.com/workitem/2408

全球.asax:

        .Register(Component
                    .For<UserManager<ApplicationUser>>()
                    .UsingFactoryMethod((kernel, creationContext) =>
                        new TempoUserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext(ASPUserDatabaseConnectionString))))
        .LifestylePerWebRequest()
                    )
        .Register(Component
                    .For<RoleManager<IdentityRole>>()
                    .UsingFactoryMethod((kernel, creationContext) =>
                        new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext(ASPUserDatabaseConnectionString))))
        .LifestylePerWebRequest()
                    )

服务层代码:

public class GenericService

    protected IRepository _repository;
    protected UserManager<ApplicationUser> _userManager;

    public GenericService(IRepository repository, UserManager<ApplicationUser> userManager)
    
        _repository = repository;
        _userManager = userManager;
    

    public ApplicationUser GetCurrentLoggedInUser()
    
        //Error is thrown when calling this
        return _userManager.FindById(HttpContext.Current.User.Identity.GetUserId());
    
 

下面是堆栈跟踪,

System.NotSupportedException: A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.
   at System.Data.Entity.Internal.ThrowingMonitor.Enter()
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<GetResultsAsync>d__e.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Data.Entity.Internal.LazyAsyncEnumerator`1.<FirstMoveNextAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Data.Entity.Infrastructure.IDbAsyncEnumerableExtensions.<FirstOrDefaultAsync>d__25`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   **at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNet.Identity.AsyncHelper.RunSync[TResult](Func`1 func)
   at Microsoft.AspNet.Identity.UserManagerExtensions.FindById[TUser,TKey](UserManager`2 manager, TKey userId)
   at Tempo.BusinessLogics.Services.GenericService.GetCurrentLoggedInUser()
   at Tempo.BusinessLogics.Services.GenericService.GetCurrentLoggedInUserID()
   at Tempo.BusinessLogics.Services.TimeService.UpdateSignOfChildDetails(EntryLog toUpdate, Boolean targetSignState)
   at Tempo.BusinessLogics.Services.TimeService.SignEntries(SignOffs sgnOffs, Byte flag)
   at Tempo.Controllers.TimeEntryController.SignOffAll(String cbxStatus)**
   at lambda_method(Closure , ControllerBase , Object[] )
   at System.Web.Mvc.ActionMethodDispatcher.<>c__DisplayClass1.<WrapVoidAction>b__0(ControllerBase controller, Object[] parameters)
   at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass48.<InvokeActionMethodFilterAsynchronouslyRecursive>b__41()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass33.<BeginInvokeActionMethodWithFilters>b__32(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<>c__DisplayClass2b.<BeginInvokeAction>b__1c()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult)
   at System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   at System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult)
   at System.Web.Mvc.Controller.<BeginExecute>b__15(IAsyncResult asyncResult, Controller controller)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   at System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult)
   at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult)
   at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
   at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

【问题讨论】:

您如何创建_userManager 并使用它? 谢谢,我已经更新了服务层代码,它显示了它是如何注入其中的,Castle Windsor 创建并将 UserManager 注入到我正在使用它的服务层中,就像它在函数中一样。 我的猜测是,如果您每次致电 GetCurrentLoggedInUser() 时都会收到一个新的 UserManager&lt;ApplicationUser&gt;,那么您将不会遇到此问题。每个上下文只允许一个异步调用。我以前没有使用过 Windsor,但 LifestylePerWebRequest() 听起来是正确的选择,但也许它会为不同的请求返回相同的实例?尝试在 GetCurrentUser 中创建一个新的 UserManager,看看问题是否消失,不是说这是解决方案,而是缩小问题范围。 【参考方案1】:

也许你忘了await async 函数,然后下一条语句试图在单个连接上执行两个查询?

【讨论】:

【参考方案2】:

听起来您正在创建两个上下文,它们都属于同一类型的ApplicationDbContext。当 EF 检测到对同一上下文同时发生两个调用时,您会收到错误。

您要么必须为每个 Web 请求创建一个上下文实例,要么将上下文拆分为它的组件部分,这样两者都可以在没有冲突的情况下注入。

【讨论】:

以上是关于UserManager 错误 - 在前一个异步操作完成之前在此上下文上启动了第二个操作的主要内容,如果未能解决你的问题,请参考以下文章

EF 错误:在前一个异步操作完成之前在此上下文上启动了第二个操作

分页后对 UserManager<T> 进行额外的异步调用

在前一个异步操作完成之前,在此上下文上启动了第二个操作。使用“等待”来确保

IAuthenticationFilter 中的 C# Ninject Web API 异步查询导致实体框架中的多个操作错误

userManager.AddToRoleAsync() - 错误:角色不存在

UserManager.AddToRole 不工作 - 外键错误