经过次要代码修改后,“无法访问已处置的对象”

时间:2014-12-06 23:07:01

标签: asp.net ninject asp.net-identity-2

使用ASP.NET MVC5,EF6& Ninject as Backend,AngularJS作为基于令牌的auth(JWT)的前端。

我们最近必须在用户名中启用@chars。基于Startup.cs中的this answer(由Ninject注册码调用,见下文),我们更换了

UserManagerFactory = () => new ApplicationUserManager(new UserStore<IdentityUser>(new SecurityDbContext()));

var userManager = new ApplicationUserManager(new UserStore<IdentityUser>(new SecurityDbContext()));
var validator = new UserValidator<IdentityUser>(userManager)
{
    AllowOnlyAlphanumericUserNames = false
};
userManager.UserValidator = validator;
UserManagerFactory = () => userManager;

这允许用@符号注册用户名。但是,登录到应用程序(即使使用“普通”用户名)也会出现错误:虽然服务器启动后的第一次登录正常工作,但任何后续登录都会产生以下异常:

Cannot access a disposed object.
Object name: 'ApplicationUserManager'.

详细错误消息:

Source Error: 
Line 18:         public override async Task FindAsync(string userName, string password)
Line 19:         {
Line 20:             var result = await base.FindAsync(userName, password);
Line 21:             if (result == null)
Line 22:             {

Source File: 
xyz\Infrastructure\ApplicationUserManager.cs    Line: 20 

Stack Trace: 

[ObjectDisposedException: Cannot access a disposed object.Object name: 'ApplicationUserManager'.]   Microsoft.AspNet.Identity.UserManager`1.ThrowIfDisposed() +99   Microsoft.AspNet.Identity.d__15.MoveNext() +128   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52   System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() +24   xyz.Infrastructure.d__0.MoveNext() in xzy\Infrastructure\ApplicationUserManager.cs:20   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52   System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() +24   xyz.Infrastructure.d__0.MoveNext() in xyz\Infrastructure\ApplicationOAuthProvider.cs:39   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52   System.Runtime.CompilerServices.TaskAwaiter.GetResult() +21   Microsoft.Owin.Security.OAuth.d__3a.MoveNext() +862   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52   System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() +24   Microsoft.Owin.Security.OAuth.d__1e.MoveNext() +2335   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52   System.Runtime.CompilerServices.TaskAwaiter.GetResult() +21   Microsoft.Owin.Security.OAuth.d__0.MoveNext() +1728   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52   System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() +24   Microsoft.Owin.Security.Infrastructure.d__0.MoveNext() +664   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52   System.Runtime.CompilerServices.TaskAwaiter.GetResult() +21   Microsoft.Owin.Security.Infrastructure.d__0.MoveNext() +937   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52   System.Runtime.CompilerServices.TaskAwaiter.GetResult() +21   Microsoft.Owin.Security.Infrastructure.d__0.MoveNext() +937   System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +22   Microsoft.Owin.Host.SystemWeb.Infrastructure.ErrorState.Rethrow() +33   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +150   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.EndFinalWork(IAsyncResult ar) +42   System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +415   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

我想这与Ninject有关,所以这里有更多背景:上面改变的代码是从NinjectWebCommon.cs调用的:

kernel.Bind<IUserService>()
    .To<UserService>()
    .WithConstructorArgument("userManager", Startup.UserManagerFactory());

1 个答案:

答案 0 :(得分:3)

问题:这是对象生命周期错误。

解决方案:使用以下代码替换您的代码。

UserManagerFactory = () => 
{
    var userManager = new ApplicationUserManager(new UserStore<IdentityUser>(new SecurityDbContext()));
    var validator = new UserValidator<IdentityUser>(userManager)
    {
        AllowOnlyAlphanumericUserNames = false
    };
    userManager.UserValidator = validator;

    return userManager;
};

<强>解释

  • 每当您的控制器需要IUserService时,Ninject就会继续,并希望构建一个新的UserService
  • 如果没有userManager,则无法调用UserService(IUserManager userManager)构造函数,因此Ninject会按照配置调用Startup.UserManagerFactory()
  • 在您的情况下,UserManagerFactory是一个lambda表达式,它返回捕获的变量userManager。这将始终是相同的实例。
  • 这是第一次按预期工作。处理完请求后,您的用户管理器实例会调用Dispose
  • 当需要处理下一个请求时,再次使用已经处理的实例。这将失败。
  • 更正的版本也是lambda表达式,但这次我们每次都创建一个新实例。