【问题标题】:ApplicationUserManager doesn't use my custom UserStore implementationApplicationUserManager 不使用我的自定义 UserStore 实现
【发布时间】:2015-04-10 13:07:09
【问题描述】:

我使用 ASP.NET Identity 创建了一个新的 MVC5 应用程序。我没有更改很多文件。这是我得到的错误:

项目中的以下更改与 VisualStudio 模板不同:

ApplicationUserManager.cs

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 ...
    }
}

我的 DependencyResolver 是 Ninject。我为它创建了以下绑定:

Bind<IMyDbContextFactory>().To<MyDbContextFactory>().InSingletonScope();
Bind<IUserStore<User>>().To<UserStore>().WithConstructorArgument("factory", factory => Kernel.Get<MyDbContextFactory>());

UserStore.cs

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 ...
}

为了完整起见,用户实体、DbContext 和我用来在UserStore.cs 中检索 DbContext 的工厂

用户.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; }
}

MyDbContextFactory.cs

public class MyDbContextFactory : IMyDbContextFactory
{
    public IMyDbContext CreateContext()
    {
        return new MyDbContext();
    }
}

MyDbContext.cs

public class MyDbContext : DbContext, IMyDbContext
{
    public MyDbContext()
        : base("MyDbContextConnection")
    {
        Configuration.LazyLoadingEnabled = false;
        Configuration.ProxyCreationEnabled = false;

        Database.Initialize(true);
    }

    // DbSets, OnModelCreating and other stuff ...
}

异常意味着 UserManager 为空。但事实并非如此:

看来ApplicationUserManager 并没有真正使用(或设置)我注入的UserStore。但这是为什么呢?

【问题讨论】:

  • 如何将UserManager 输入控制器?默认情况下,它是从OwinContext 中提取的,而不是从您的 DI 中提取的。在您的异常消息中,UserManager 似乎为空。
  • UserManager 仍然是从OwinContext 中提取的。我没有更改应用程序的那部分。我仍然在Startup.Auth.cs 中使用app.CreatePerOwinContext&lt;ApplicationUserManager&gt;(ApplicationUserManager.Create);。不,UserManager 不为空。 (我在我的问题中添加了截图)
  • 因此,如果您逐步执行 `ApplicationUserManager.Create` 方法。您是否收到从DependencyResolver 返回给您的UserStoreDependencyResolver 是否解决了任何其他对象?
  • DependencyResolver 可以正常工作。我也尝试直接使用具体类但没有成功。这不是问题。与此同时,我发现了问题所在。我现在正在发布答案。感谢您的帮助。

标签: asp.net-mvc asp.net-mvc-5 asp.net-identity asp.net-identity-2


【解决方案1】:

好的,我发现了,但这是一个艰难的过程。

ApplicationUserManager 调用的UserStore 的第一个方法是SetPasswordHashAsync。 (不要问我为什么-.-)

我对该方法的实现返回了null。这是错误的,有两个原因

  1. 我不应该写return null;,而是return Task.FromResult&lt;Task&gt;(null);,因为它是一个异步方法。 (或抛出异常)。因此,我收到了那个没用的 YSOD。
  2. UserManager 首先调用SetPasswordHashAsync。再说一次,不要问我为什么。由于我使用/Account/RegisterAction注册了一个新用户,所以我根本没想到UserManager首先尝试设置密码。我的意思是,还没有用户。这就是为什么我想注册一个。什么鬼?

总结一下:UserManager 确实使用了我的 UserStore,但并没有像我预期的那样。

【讨论】:

  • SetPasswordHashAsync 实际上更新了类实例上的值,而不是数据库中的值。检查框架实现的源代码 - 你会明白为什么这样做。
猜你喜欢
  • 2014-07-29
  • 2017-01-09
  • 1970-01-01
  • 1970-01-01
  • 2015-06-25
  • 1970-01-01
  • 2016-08-09
  • 1970-01-01
  • 2016-08-20
相关资源
最近更新 更多