Re: ApplicationUserManager.Create dependency issue (issue 2297)

Jul 8, 2014 at 6:23 PM
With reference to Issue 2297

I speak with no authority, only referencing what I did to get this to work. There is a lot of confusion over the use of Identity with OWIN, mainly from the sample code and lack of authoritative documentation thus far. It does look like this needs tidying up, but I am not sure how that should be done as so much of it is internal code. I have found however that I can completely decouple my code from it as of Identity 2.0.1 (untested with Identity 2.1 as yet).

ApplicationDbContext

The samples include app.CreatePerOwinContext(ApplicationDbContext.Create);

From what I have found, there is no internal dependency on owinContext.Get<ApplicationDbContext>(), so unless you intend to use the IOwinContext as a (poor mans) service locator you don't need to do this. Instead you can inject your per-request ApplicationDbContext from your IoC container into the classes that require it.

ApplicationUserManager.Create

As you have seen, this is just a factory method which is then passed to OWIN through app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);. The intent is to create a single ApplicationUserManager per request. This is then used internally by using the IOwinContext as a service locator. I read somewhere that one of the team said this was because they had no IoC injection to use, so they use the context dictionary instead.

The IOwinContext acts as a service locator for other services, such as the IDataProtectionProvider. This is then provided to the factory in the IdentityFactoryOptions. But from what I can work out, the IDataProtectionProvider is a single instance, not per-request.

But this is where it gets strange. The IdentityFactoryOptions.Provider property is actually set to the factory method you originally provided (in this case ApplicationUserManager.Create). So the factory method is passed state that includes itself.

Another way

The default IDataProtectionProvider that is provided is a DpapiDataProtectionProvider. This is created by the CookieAuthenticationMiddleware. It seems like nothing is done with this until the application pushes a request through the pipeline. The DpapiDataProtectionProvider will have issues in a web farm such as Azure so you may want to replace this anyway.

Therefore you can:
  1. Let your IoC framework generate the single instance IDataProtectionProvider, and register that with Owin in Startup using app.SetDataProtectionProvider(idp) - this makes sense as you will be setting up your IoC framework here as well, so you have access to the single instance at this point.
  2. Subtype the ApplicationUserManager and provide a ctor which allows your IoC framework to inject an IDataProtectionProvider (or provide a factory method to your IoC so this work is not done in the ctor but is still controlled by the IoC injector and lifetime scopes)

    AppUserManager(AppUserStore store, IDataProtectionProvider dpp)
  3. Use the following code as the Owin factory method (Autofac specific, but you can substitute any other IoC container).

    app.CreatePerOwinContext<AppUserManager>((o, context) => context.GetAutofacLifetimeScope().Resolve<AppUserManager>()); // returns the per-request AppUserManager from the IoC resolver
  4. Now you can apply the same technique to inject the EmailService, SmsService and any other services into the ApplicationUserManager and no longer worry about the IdentityFactoryOptions
  5. You can also use your IoC framework to inject an IDataProtectionProvider anywhere you need a new ApplicationUserManager, removing your dependency on the IdentityFactoryOptions<>