How to register custom UserStore & UserManager in DI

烂漫一生 提交于 2019-12-31 13:12:23

问题


Here is my setup:

public class ApplicationUser : IdentityUser<Guid>
{
}
public class ApplicationRole : IdentityRole<Guid>
{
}
public class ApplicationUserLogin : IdentityUserLogin<Guid>
{
}
public class ApplicationUserClaim : IdentityUserClaim<Guid>
{
}
public class ApplicationRoleClaim : IdentityRoleClaim<Guid>
{
}

Here is the definition of my UserStore

public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, MyContext, Guid>
{
    public ApplicationUserStore(MyContext context, IdentityErrorDescriber describer = null)
        : base(context, describer)
    {
    }
}

Here is the definition of my UserManager

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor,
        IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
        IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
        IdentityErrorDescriber errors, IEnumerable<IUserTokenProvider<ApplicationUser>> tokenProviders,
        ILoggerFactory logger, IHttpContextAccessor contextAccessor)
        : base(
            store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors,
            tokenProviders, logger, contextAccessor)
    {
    }
}

Here is the definition of my DbContext:

public class MyContext : IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
{
    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    }
}

And here is my Startup.cs

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<MyContext>(options => options.UseSqlServer(Configuration.Get("Data:DbConnection")));

        services.AddIdentity<ApplicationUser, ApplicationRole>()
            .AddEntityFrameworkStores<MyContext, Guid>()
            .AddUserStore<ApplicationUserStore>()
            .AddRoleStore<ApplicationRoleStore>()
            .AddUserManager<ApplicationUserManager>()
            .AddRoleManager<ApplicationRoleManager>()
            .AddDefaultTokenProviders();

        var builder = new ContainerBuilder();
        builder.Populate(services);
        var container = builder.Build();
        return container.Resolve<IServiceProvider>();
    }

The dependency of this constructor will work:

public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)

This one won't:

public AccountController(ApplicationUserManager userManager, SignInManager<ApplicationUser> signInManager)

Anyone has an idea on what I'm doing wrong?


回答1:


DI in general is intended for interface-driven development; .AddUserManager<ApplicationUserManager>() specifies an implementation UserManager<>, not the service interface. That means that it's still expecting you to get UserManager<ApplicationUser> and only use it that way; it'll give you an ApplicationUserManager.

I'm assuming that you have additional methods you want to use on your ApplicationUserManager. If not, just use the dependency constructor the way it works and enjoy the interface-driven development. If so, you have 3 options:

  1. Use extension via composition rather than inheritance. Rather than inheriting from UserManager<>, write ApplicationUserManager as a wrapper class; you can include it in the constructor. This should give you all the functionality you need inside of the ApplicationUserManager.

  2. Add it as-is to the DI framework yourself. This isn't as difficult as it sounds, since the UserManager<> has no real state itself:

    services.AddScoped<ApplicationUserManager>();
    

    The disadvantage here is that you'll actually have two UserManager<> objects for the user's scope; there could be some inefficiencies as a result. From the state of the current code, I don't think it is.

  3. Write it as extension methods. If you have a number of dependencies and not just the UserManager<>'s base functionality, this could be really complex.




回答2:


I am now on ASP.NET Core 1.1 and this behavior has been fixed.

I can easily implement my own UserManager and UserStore, then bootstrap the app as following:

// identity models
services
    .AddIdentity<ApplicationUser, ApplicationRole>()
    .AddEntityFrameworkStores<ApplicationDbContext, Guid>()
    .AddUserManager<ApplicationUserManager>()
    .AddUserStore<ApplicationUserStore>()
    .AddDefaultTokenProviders();

and inject both UserManager and UserStore into my Controller, without any problem:

public AccountController(
    IIdentityServerInteractionService interaction,
    IClientStore clientStore,
    IHttpContextAccessor httpContextAccessor,
    ApplicationUserManager userManager,
    SignInManager<ApplicationUser> signInManager,
    IEmailSender emailSender,
    ISmsSender smsSender,
    ILoggerFactory loggerFactory)
{
    _interaction = interaction;
    _userManager = userManager;
    _signInManager = signInManager;
    _emailSender = emailSender;
    _smsSender = smsSender;
    _logger = loggerFactory.CreateLogger<AccountController>();
    _account = new AccountService(_interaction, httpContextAccessor, clientStore);
}


来源:https://stackoverflow.com/questions/30453567/how-to-register-custom-userstore-usermanager-in-di

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!