How to configure ASP.NET Identity ApplicationUserManager with StructureMap

Mohammad Zare picture Mohammad Zare · Sep 17, 2014 · Viewed 17.4k times · Source

I am using asp.net identity in my project and using structuremap as DI framework. the problem is when i use constructor injection then ApplicationUserManager not configured all of it's members e.g TokenProvider, ...

this is my ApplicationUserManager class:

public class ApplicationUserManager : UserManager<User, long>
{
    public ApplicationUserManager(IUserStore<User, long> store)
        : base(store)
    {
    }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        var manager = new ApplicationUserManager(new CustomUserStore(context.Get<InsuranceManagementContext>()));

        // Configure the application user manager
        manager.UserValidator = new UserValidator<User, long>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = false
        };

        manager.PasswordValidator = new PasswordValidator
        {
            RequireDigit = true,
            RequiredLength = 8,
            RequireLowercase = false,
            RequireNonLetterOrDigit = true,
            RequireUppercase = false
        };

        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider =
                new DataProtectorTokenProvider<User, long>(dataProtectionProvider.Create("TEST"));
        }

        return manager;
    }
}

this is Startup.Auth class:

public partial class Startup
{
    // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {
        app.CreatePerOwinContext(InsuranceManagementContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            ExpireTimeSpan = TimeSpan.FromHours(2.0),
            AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
        });
    }
}

and its my AccountController:

public class AccountController : BaseController
{
    private ApplicationUserManager _userManager;
    public ApplicationUserManager UserManager
    {
        get
        {
            return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        private set
        {
            _userManager = value;
        }
    }

    public AccountController(ApplicationUserManager userManager)
    {
        UserManager = userManager;
    }
}

my question is how can i configure my ApplicationUserManager with structuremap? if i set it as the below code it works but i don't know it is a good solution or not:

ObjectFactory.Initialize(x =>
{
     ...
     x.For<ApplicationUserManager>().Use(() => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>());
     ...
});

please hint me if there is a better solution and if it is ok then what is the best lifetime for it? HttpContextScope, Singleton, ...?

Answer

Rui picture Rui · Mar 9, 2016

Before you create the StructureMap configuration for this, it helps to know how you would create it manually, i.e., if you actually "new up" everything yourself.

UserManager has a dependency on IUserStore, and its EntityFramework implementation (UserStore) has a dependency on DbContext. Doing everything manually would look like this:

var dbContext = new IdentityDbContext("Your ConnectionString Name");
var userStore = new UserStore<IdentityUser>(dbContext);
var userManager = new UserManager<IdentityUser>(userStore);

(Replace IdentityUser with your custom user, if you are using one)

You can then configure UserManager like this:

userManager.PasswordValidator = new PasswordValidator
{
    RequiredLength = 6
};

The most complicated part about configuring userManager is related to the UserTokenProvider (that uses the data protection api), if you would do it manually it would look like this:

var dataProtectionProvider = new DpapiDataProtectionProvider("Application name");
var dataProtector = dataProtectionProvider.Create("Purpose");
userManager.UserTokenProvider = new DataProtectorTokenProvider<IdentityUser>(dataProtector);

Here's an example of a StructureMap registry (you can extrapolate from this example and adapt it to your own needs):

 public DefaultRegistry() {
        Scan(
            scan => {
                scan.TheCallingAssembly();
                scan.WithDefaultConventions();
                scan.With(new ControllerConvention());
            });


        For<IUserStore<IdentityUser>>()
            .Use<UserStore<IdentityUser>>()
            .Ctor<DbContext>()
            .Is<IdentityDbContext>(cfg => cfg.SelectConstructor(() => new IdentityDbContext("connection string")).Ctor<string>().Is("IdentitySetupWithStructureMap"));

        ForConcreteType<UserManager<IdentityUser>>()
            .Configure
            .SetProperty(userManager => userManager.PasswordValidator = new PasswordValidator
            {
                RequiredLength = 6
            })
            .SetProperty(userManager => userManager.UserValidator = new UserValidator<IdentityUser>(userManager));                
    } 

I wrote a blog post about this, it explains the process that lead to this configuration, there's also a link to an example on github of an MVC project where, using this configuration, you can create, list and delete users.