I am having problems creating a custom UserStore using dependency injection when creating an ApplicationUserManager using the OWIN request pipeline.
Background
I am trying to migrate the user functionality in our web application from using the SimpleMembership to the new ASP.NET Identity. When starting a new MVC 5 project, the default implementation of the single page application uses ASP.Identity, using Entity Framework to implement the UserStore functionality.
In my case, we are already using NHibernate as the ORM, and using ninject to implement the unit of work pattern so that we had one NHibernate session per request, and I wanted to make the ASP.Identity work with our existing framework.
To this end, I created a custom UserStore, which could be created by injecting the relevant repositories/nhibernate session, etc. This could then be injected into the Controller's constructor using Ninject, rather than using the default implementation's GetOwinContext functionality.
In order to do this, I had commented out the following line in the ConfigureAuth(IAppBuilder app) method of the Startup, which by default creates the UserManager class:
// app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
Instead, I used the NinjectWebCommon created when installing the Ninject.Web.Common.Webhost nuget package to create the relevant bindings.
This implementation worked fine with some of the UserManager operations, but with some operations, such as ResetPasswordAsync, it fails because the default ApplicationUserManager implementation is not called, and so the UserTokenProvider in the UserManager class is never set:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) { var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>())); // Configure validation logic for usernames manager.UserValidator = new UserValidator<ApplicationUser>(manager) { AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true }; // Configure validation logic for passwords manager.PasswordValidator = new PasswordValidator { RequiredLength = 6, RequireNonLetterOrDigit = true, RequireDigit = true, RequireLowercase = true, RequireUppercase = true, }; // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user // You can write your own provider and plug in here. manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser> { MessageFormat = "Your security code is: {0}" }); manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser> { Subject = "Security Code", BodyFormat = "Your security code is: {0}" }); manager.EmailService = new EmailService(); manager.SmsService = new SmsService(); var dataProtectionProvider = options.DataProtectionProvider; if (dataProtectionProvider != null) { manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity")); } return manager; }
Therefore, the UserTokenProvider is not set.
Problem
I want to use the OWIN pipeline, because Visual Studio's default implementation of the ApplicationUserManager class injects the IDataProtectionProvider in its Create callback method. However, I also want to create my UserStore using dependency Injection, and I do not know how to create a UserStore within this method using dependency injection.
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) { // WANT TO CREATE THE USER STORE USING NINJECT DEPENDENCY INJECTION HERE // var userStore = ... var manager = new ApplicationUserManager(userStore); }
I have tried to get around this limitation by using the Ninject.Web.Common.OwinHost nuget package and creating the kernel within the Startup class.
public void ConfigureAuth(IAppBuilder app) { // Setup app.UseNinjectMiddleware(CreateKernel); }
However, the Ninject.Web.Common.OwinHost does not expose its Kernel, so I am unable to use service location pattern to inject the values into my custom UserStore in the Create callback.
I have also tried to create a singleton Kernel, and register this using app.CreatePerOwinContext(CreateKernel) with the relevant delegate, so I could later access the Kernel, but when I call context.Get() it just returns null.
Question
How can I register a callback function with CreatePerOwinContext to create a custom UserManager which uses a custom UserStore, and then use Ninject to create the custom UserStore using dependency injection in the Create callback, so that I also have access to the IdentityFactoryOptions which Owin uses to inject the user token provider?
Ninject is a lightweight dependency injection framework for . NET applications. It helps you split your application into a collection of loosely-coupled, highly-cohesive pieces, and then glue them back together in a flexible manner.
OWIN allows web apps to be decoupled from web servers. It defines a standard way for middleware to be used in a pipeline to handle requests and associated responses. ASP.NET Core applications and middleware can interoperate with OWIN-based applications, servers, and middleware.
For info:
It is possible to register the kernel as a singleton so that the same kernel can be used by the ninject middleware and also registered within the owin context.
public static StandardKernel CreateKernel() { if (_kernel == null) { _kernel = new StandardKernel(); _kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>(); _kernel.Load(Assembly.GetExecutingAssembly(), Assembly.Load("Super.CompositionRoot")); } return _kernel; }
The callback function app.CreatePerOwinContext(ApplicationUserManager.Create), will call the ApplicationUserManager.Create rather than register it to be called at a later point during the setup. Therefore, the CreateKernel function needs to be registered before the ApplicationUserManager's Create callback or you will get a null reference exception if you try to get the kernel from the owin context within that method.
public void ConfigureAuth(IAppBuilder app) { app.CreatePerOwinContext(CreateKernel); app.UseNinjectMiddleware(CreateKernel); app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); }
This will allow you to access the kernel to create a custom UserStore within the ApplicationUserManager's Create callback:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) { var kernel = context.Get<StandardKernel>(); var userStore = kernel.Get<IUserStore<User, int>>(); var manager = new ApplicationUserManager(userStore); //... }
I know that in general dependency injection should be favoured over service location, but in this context I couldn't see a way around it - unless anybody has any better suggestions?
This will allow you to use Ninject to implement the unit of work patter leveraging Ninject's InRequestScope().OnDeactivation functionality. I'm aware that the UserManager class has a per request lifetime, but didn't know the most the most appropriate way to commit any outstanding transactions on request finish.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With