I created a new MVC5 Application with ASP.NET Identity. I haven't changed lot of the files. This is the error I get:
The following changes in the project differ from the VisualStudio template:
public class ApplicationUserManager : UserManager<User>
{
public ApplicationUserManager(IUserStore<User> userStore)
: base(userStore)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
// Use DI to resolve the UserStore
var userStore = (IUserStore<User>) DependencyResolver.Current.GetService(typeof (IUserStore<User>));
var manager = new ApplicationUserManager(userStore);
// rest is same as in the template ...
}
}
My DependencyResolver is Ninject. I created the following Bindings for it:
Bind<IMyDbContextFactory>().To<MyDbContextFactory>().InSingletonScope();
Bind<IUserStore<User>>().To<UserStore>().WithConstructorArgument("factory", factory => Kernel.Get<MyDbContextFactory>());
public class UserStore : IUserStore<User>,
IUserLockoutStore<User, string>,
IUserPasswordStore<User>,
IUserTwoFactorStore<User, string>,
IUserEmailStore<User>
{
private readonly IMyDbContextFactory _factory;
public UserStore(IMyDbContextFactory factory)
{
_factory = factory;
}
public void Dispose()
{
// Nothing to dispose here
}
public Task CreateAsync(User user)
{
using (var context = _factory.CreateContext())
{
// TODO: Validation
context.Users.Add(user);
var result = context.SaveChanges();
return Task.FromResult(result);
}
}
// the rest of the implementend methods from the interfaces ...
}
And for the sake of completeness the User entity, the DbContext and the factory I use to retrieve the DbContext in UserStore.cs
public class User : IUser
{
public string Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public object PhoneNumber { get; set; }
public int AccessFailedCount { get; set; }
public bool LockoutEnabled { get; set; }
public DateTime? LockoutEndDateUtc { get; set; }
public bool TwoFactorEnabled { get; set; }
public virtual ICollection<UserRole> ApplicationUserRoles { get; set; }
public virtual ICollection<UserLogin> ApplicationUserLogins { get; set; }
}
public class MyDbContextFactory : IMyDbContextFactory
{
public IMyDbContext CreateContext()
{
return new MyDbContext();
}
}
public class MyDbContext : DbContext, IMyDbContext
{
public MyDbContext()
: base("MyDbContextConnection")
{
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
Database.Initialize(true);
}
// DbSets, OnModelCreating and other stuff ...
}
The Exception implies that UserManager is null. But that's not true:
It seems that ApplicationUserManager
doesn't really use (or sets) my injected UserStore. But why is that?
OK I found it out, but it was a tough one.
The first method of the UserStore
that gets called from the ApplicationUserManager
is SetPasswordHashAsync
. (Don't ask me why -.-)
My implementation of that method returned null
. That was wrong for two reasons
return null;
but return Task.FromResult<Task>(null);
, since it's an async method. (Or throw an Exception). Because of that, I received that useless YSOD.SetPasswordHashAsync
first. Again, don't ask me why. Since I used the /Account/Register
Action to register a new user, I simply didn't expect that the UserManager first tries to set the password. I mean, there is no user yet. That's why I want to register one. WTF?To summarize: The UserManager did actually use my UserStore, but not as I expected it.