Identity: Create simple constructor for UserManager for console applications

Created on 9 Jul 2014  路  7Comments  路  Source: aspnet/Identity

The current UserManager takes in dependencies of type: IUserStore<TUser> , IOptionsAccessor<IdentityOptions> , IPasswordHasher , IUserValidator<TUser> , IPasswordValidator<TUser> , IClaimsIdentityFactory<TUser>

It is easy to get an instance in web application through DI but in cases where users wants to instantiate the UserManager locally, they have to provide all these dependencies. It would be good to have one with default constructor or a static method that returns a UserManager with defaults set

var usermanager = UserManager.Create(IUserStore);

Most helpful comment

One way of achieving this could be if you create your own instance of IServiceCollection.

Below is the example code

  public class AspNetIdentityCredentialProvider
    {
        private readonly IServiceCollection _serviceCollection;

        public AspNetIdentityCredentialProvider()
        {
            _serviceCollection = new ServiceCollection();
            _serviceCollection.AddIdentity<IdentityUser, IdentityRole>()
                .AddEntityFrameworkStores<IdentityDbContext<IdentityUser>>()
                .AddDefaultTokenProviders();
            _serviceCollection.AddDbContext<IdentityDbContext<IdentityUser>>(options =>
            {
                options.UseSqlServer(connString);
            });
        }

Then you're able to do whatever you desire

            var um = _serviceCollection.BuildServiceProvider().GetService<UserManager<IdentityUser>>();
            try
            {
               var u= await um.FindByNameAsync("..");

All 7 comments

We rely on application startup to setup up the dependencies correctly so that they can be resolved later via DI without violating the layering: some of those dependencies live in Microsoft.AspNet.Identity.EntityFramework.dll and Microsoft.AspNet.Idetity.Authentication.dll, while UserManager is defined in the root Microsoft.AspNet.Identity.dll.

A possible alternative to DI is to wire up explicitly the dependencies in a method that is executed once per UserManager instance, e.g. similar to the OnConfiguring method that EF's DbContext provides and that can be overridden in a derived DbContext.

But before we try to do anything like that we should discuss what exactly it mean to "get the UserManager locally". It is not clear to me that there is a compelling scenario there for us.

A simple example is a console application where we need to instantiate usermanager without setting up DI. I was working on populating a database or even running a one time migration code and creating a usermanager object felt tedious.

In 2.0 instantiating usermanager was as simple as

var usermanager = new UserManager<User>(new UserStore<User>(new DbContext()));   

With current stack, the constructor takes more dependencies which makes coding a little more work than needed. I would agree that this doesn't qualify for the average case scenario but this is one experience we have weakened from 2.0. Even in the unit test, if we look at the MockHelpers class, setting up UserManager is through ServiceCollection. Should that be the case all the time ?

First there was the async infection, now there is the DI infection :) Until we have a mechanism for DI to resolve constructors better we can't really do much here in terms of adding syntactic sugar constructors to the base class. We could put that in some helper static factory method to wire up everything with the defaults, but I think we should wait to see if we have real use cases like Diego says. You should be able to use DI in a console app as well.

I just saw this issue after having some trouble myself w/ console app...

Identity targets AspNet primarily, can revisit this if we want to make non aspnet scenarios easier in the future

This can be helpful on some situations where I need to seed the database on startup and add users through the UserManager.

I've tried this:

UserManager<ApplicationUser> userManager = (UserManager<ApplicationUser>)httpContextAccessor
                    .HttpContext.ApplicationServices.GetService(typeof(UserManager<ApplicationUser>));

but at this stage (database seeding on startup) there is no HttpContext

One way of achieving this could be if you create your own instance of IServiceCollection.

Below is the example code

  public class AspNetIdentityCredentialProvider
    {
        private readonly IServiceCollection _serviceCollection;

        public AspNetIdentityCredentialProvider()
        {
            _serviceCollection = new ServiceCollection();
            _serviceCollection.AddIdentity<IdentityUser, IdentityRole>()
                .AddEntityFrameworkStores<IdentityDbContext<IdentityUser>>()
                .AddDefaultTokenProviders();
            _serviceCollection.AddDbContext<IdentityDbContext<IdentityUser>>(options =>
            {
                options.UseSqlServer(connString);
            });
        }

Then you're able to do whatever you desire

            var um = _serviceCollection.BuildServiceProvider().GetService<UserManager<IdentityUser>>();
            try
            {
               var u= await um.FindByNameAsync("..");
Was this page helpful?
0 / 5 - 0 ratings