Using ASP.NET MVC5, EF6 & Ninject as Backend, AngularJS as frontend with token based auth (JWT).
We recently had to enable @ chars in the user names. Base on this answer in the Startup.cs (called by Ninject registration code, see below), we replaced
UserManagerFactory = () => new ApplicationUserManager(new UserStore<IdentityUser>(new SecurityDbContext()));
with
var userManager = new ApplicationUserManager(new UserStore<IdentityUser>(new SecurityDbContext()));
var validator = new UserValidator<IdentityUser>(userManager)
{
AllowOnlyAlphanumericUserNames = false
};
userManager.UserValidator = validator;
UserManagerFactory = () => userManager;
This allows the registration of user name with @ signs as wished. However, logging into the application (even with "normal" usernames), became buggy: While the first login after start of the server works as usual, any subsequent login creates the following exception:
Cannot access a disposed object.
Object name: 'ApplicationUserManager'.
Detailed error message:
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
I guess it has something to do with Ninject, so here's a bit more background: the above changed code is called from the NinjectWebCommon.cs:
kernel.Bind<IUserService>()
.To<UserService>()
.WithConstructorArgument("userManager", Startup.UserManagerFactory());
Problem: This is an object lifetime error.
Solution: Replace your code with the following.
UserManagerFactory = () =>
{
var userManager = new ApplicationUserManager(new UserStore<IdentityUser>(new SecurityDbContext()));
var validator = new UserValidator<IdentityUser>(userManager)
{
AllowOnlyAlphanumericUserNames = false
};
userManager.UserValidator = validator;
return userManager;
};
Explanation:
IUserService, Ninject goes ahead and wants to construct a new UserService.UserService(IUserManager userManager) constructor cannot be called without a userManager, so Ninject calls Startup.UserManagerFactory(), as configured.UserManagerFactory is a lambda expression that returns the captured variable userManager. This will always be the same instance.Dispose is called on your user manager instance.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With