用户管理器错误 - 在前一个异步操作完成之前,此上下文上启动了第二个操作。

11
我正在使用Identity v2.0.0.0、EF 6、Castle Windsor IOC容器和Microsoft SQL Server 2005开发我的asp.net MVC5 Web应用程序,遇到了问题。我尝试使用UserManagerExtensions的FindById()方法获取当前登录的用户,但是它抛出一个错误:“System.NotSupportedException:在上一个异步操作完成之前,在此上下文中启动了第二个操作。请使用'await'确保在调用此上下文上的另一个方法之前已完成任何异步操作。任何实例成员都不能保证是线程安全的。”
我从堆栈跟踪中理解到的是"AsyncHelper.RunSync()"引起了问题,虽然我的代码中没有使用任何异步函数,但是"FindById()"使用了AsyncHelper 参考-: 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

Global.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)

1
你是如何创建 _userManager 并使用它的? - artm
1
谢谢,我已经更新了服务层代码,并展示了它是如何被注入的。Castle Windsor将UserManager创建并注入到服务层中,在我的函数中使用它。 - Ramesh Sivaraman
6
我的猜测是,如果每次调用GetCurrentLoggedInUser()时都获取一个新的UserManager<ApplicationUser>,那么你就不会遇到这个问题。在上下文中,您只允许一个异步调用。我以前没有使用过温莎,但LifestylePerWebRequest()听起来像是正确的选项,但也许它会为不同的请求返回相同的实例?尝试在GetCurrentUser中创建一个新的UserManager,看看是否可以解决问题。我并不是说这是解决方案,而是为了缩小问题范围。 - artm
2个回答

1
也许您忘记了使用await来等待异步函数执行完成,然后下一条语句尝试在单个连接上执行两个查询?

0

看起来你正在创建两个上下文,它们都是同一类型的ApplicationDbContext。当EF检测到同时发生两个调用相同上下文的情况时,就会出现错误。

你需要为每个Web请求创建一个上下文实例,或将上下文拆分成其组件部分,以便两者都可以被注入而不会发生冲突。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接