Per request lifetime management for UserManager class in ASP.NET Identity

Per request lifetime management for UserManager class in ASP.NET Identity

  • Comments 16

Introduction

We recently released the 2.0.0-beta1 version of ASP.NET Identity. Learn more here by visiting this link. This is an update to 2.0.0-alpha1 and adds the two-factor auth feature along with a few bug fixes. To learn more about the Alpha release, please visit this link.

In this article I am going to explain the significance of the UserManager class in an application and some of the best practices when using it. I am going to use an MVC application that is created using VS 2013 RTM. In the Visual Studio 2013 RTM templates, which had the 1.0.0 version of ASP.NET Identity, we demonstrated directly instantiating the UserManager class as needed in the application. This approach had a few issues, which are explained further in this article. These have been fixed in 2.0.0-beta1.

Understanding Managers and Stores

ASP.NET Identity consists of classes called managers and stores. Managers are high-level classes which an application developer uses to perform operations in the ASP.NET Identity system, such as creating a user. Stores are lower-level classes that specify how entities, such as users and roles, are persisted. Stores are closely coupled with the persistence mechanism, but managers are decoupled from stores which means you can replace the persistence mechanism without disrupting the entire application.

The current article outlines the steps to configure the UserManager in the application. We will start with an application with Identity 1.0.0. We will migrate the solution to 2.0.0-beta1, and change the way UserManager is instantiated and used in the application. Additionally, with this approach it is possible to configure the properties on the UserManager, such as password length and complexity.

Create Application

In Visual Studio 2013 RTM create a new web application. Choose MVC

clip_image002

UserManager explained

Let us briefly look at how the UserManager class is used in the application. All user account management actions are defined in the AccountController class.

Code Snippet
  1. public AccountController()
  2.             : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
  3.         {
  4.         }
  5.  
  6.         public AccountController(UserManager<ApplicationUser> userManager)
  7.         {
  8.             UserManager = userManager;
  9.         }
  10.  
  11.         public UserManager<ApplicationUser> UserManager { get; private set; }

The controller has a UserManager property of type UserManager which is set in the constructor. The UserManager class takes in an instance of UserStore class which implements operations on the user that are persistence-specific. In our case, we have a UserStore class which implements these operations specific to EntityFramework. To persist data to/from the database the UserStore class takes in an instance of DBContext class. The UserStore class is defined in the Microsoft.AspNet.Identity.EntityFramework assembly.

Note: The rationale behind implementing this pattern is that if the developer wishes to store user information in the any other storage system (for example, Azure Table storage), all they have do is replace the ‘UserStore’ class with an Azure Table storage implementation. There would be no additional changes needed in the AccountController, and the existing application would function seamlessly.

The problem

In the current approach, if there are two instances of the UserManager in the request that work on the same user, they would be working with two different instances of the user object. An example for this would be using the one in the class property and instantiating one locally in the method under execution. In this scenario the changes made by either of them would not reflect the changes made by the other. Hence persisting these changes back to the database would lead to incorrect changes being made to the user object.

The same problem exists when you are trying to use the DBContext class in the application.

The solution

The solution to the above problem is to store a single instance of UserManager and DbContext per request and reuse them throughout the application. Since Identity hooks into the OWIN pipeline via cookie middleware, we can store the UserManager and DbContext in the OWIN context object and retrieve them as needed.

1. In the application created above, update the Identity packages to 2.0.0-beta1 from the NuGet feed. This can be done through the Manage Nuget packages window. The steps to update Nuget packages are explained here.

2. Instead of directly working with UserManager<T> class we can define a custom class, ApplicationUserManager that extends from UserManager<T>. In the project under the App_Start folder create a new file IdentityConfig.cs and add a new class ApplicationUserManager. The ApplicationUserManager should extend the UserManager class

Code Snippet
  1. public class ApplicationUserManager : UserManager<ApplicationUser>
  2.     {
  3.     }

3. The web application uses the new OWIN cookie middleware for the cookie-based authentication. During application start, the Configuration method in the Startup class is invoked, which configures all the middleware components registered in the application. In the MVC 5 template, the cookie middleware is configured through the ConfigAuth method defined in the Startup.Auth class.

Since we need to register the UserManager and DBContext class with the OWIN context during app start, we will add methods to do that in the ConfigureAuth method. The ‘CreatePerOwinContext<T>’ method is defined in the Microsoft.AspNet.Identity.Owin namespace. This method registers a static callback method which returns an instance of type <T>. This method is invoked once per request and used to obtain instance object which is used during the lifetime of the request.

4. To create a static callback method that returns an instance of DbContext , in the ApplicationDbContext class create a method as defined below

Code Snippet
  1. public static ApplicationDbContext Create()
  2.     {
  3.         return new ApplicationDbContext();
  4.     }

5. Similarly define a method in the ApplicationUserManager that returns an instance of the ApplicationUserManager.

Code Snippet
  1. public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
  2.         {
  3.             var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
  4.             return manager;
  5.         }

In the constructor of the UserManager, we need to retrieve the instance of DbContext to configure the UserStore. We can get the instance of the object from the OwinContext using the ‘Get<ApplicationDbContext>’ method that in turn returns the single instance of DbContext class created using ApplicationDbContext.Create callback method.

6. Register these two callback methods in the ConfigureAuth method through the ‘CreatePerOwinContext’ method

Code Snippet
  1. public void ConfigureAuth(IAppBuilder app)
  2.         {
  3.         app.CreatePerOwinContext<ApplicationDbContext>(ApplicationDbContext.Create);
  4.         app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
  5.          .
  6.          }

7. Next we hook this up in the AccountController class. Change the constructor and the UserManager property on the class to type ApplicationUserManager

Code Snippet
  1. public AccountController()
  2.         {
  3.         }
  4.         public AccountController(ApplicationUserManager userManager)
  5.         {
  6.             UserManager = userManager;
  7.         }
  8.         private ApplicationUserManager _userManager;
  9.         public ApplicationUserManager UserManager
  10.         {
  11.             get;
  12.             private set;
  13.         }

8. In the set property of the UserManager we need can retrieve the UserManager instance from the OWIN context. For this we have an extension method provided in the Microsoft.AspNet.Identity.Owin namespace

Code Snippet
  1. public ApplicationUserManager UserManager
  2.         {
  3.             get
  4.             {
  5.                 return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
  6.             }
  7.             private set
  8.             {
  9.                 _userManager = value;
  10.             }
  11.         }

9. Run the application and verify that a local user can be created in the application.

10. Also in the application if we need to work with the DbContext object directly we can get the instance of the class from the OWIN context as mentioned earlier using the ‘Get<T>’ method

Code Snippet
  1. var dbContext = context.Get<ApplicationDbContext>();

Configuring UserManager properties

Another advantage of following this approach is that we can configure the UserManager properties when instantiating it in a single place. For example, the UserManager by default has a password validator that validates that the supplied password is of length 6 characters. We can change this to use the new password validator in 2.0.0-beta1 which checks for additional complexity in the supplied password during registration.

To do this, simply set the PasswordValidator property in the ‘Create’ method of the ApplicationUserManager with the new ‘PasswordValidator’ class

Code Snippet
  1. public ApplicationUserManager(UserStore<ApplicationUser> userStore)
  2.             : base(userStore)
  3.         {
  4.         }
  5.         public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
  6.         {
  7.             var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
  8.             manager.PasswordValidator = new PasswordValidator
  9.             {
  10.                 RequiredLength = 10,
  11.                 RequireNonLetterOrDigit = true,
  12.                 RequireDigit = true,
  13.                 RequireLowercase = false,
  14.                 RequireUppercase = false,
  15.             };
  16.             return manager;
  17.         }

Here the PasswordValidator class is configured to verify that the supplied password has a non-alphanumeric character and a numeric character. Also the length of password should be of 10 characters length. Similarly other properties of the UserManager can be configured to be persisted through the context lifecycle.

Summary

This post shows how to get a per-request, single instance of the UserManager and DbContext classes from the OWIN context to be used throughout the application. This will form a base for additional blog posts outlining the new features in ASP.NET Identity 2.0.0-beta1.

I hope you have found this walkthrough useful. If you have any questions around ASP.NET Identity or find issues, please feel free to open bugs on the Identity Codeplex site, https://aspnetidentity.codeplex.com/ , leave comments on this blog, or ask questions or StackOverflow (tag: aspnet-identity). I can also be reached on twitter (@suhasbjoshi).


Leave a Comment
  • Please add 5 and 8 and type the answer here:
  • Post
  • Any non-trivial MVC website has DI configured anyway and should allow you to have dependencies with transient, singleton and per-request lifecycles. Just use that.

  • Will something similar be introduced for RoleManager?

  • Great explanation, but what is the best way to integrate with app.UseOAuthBearerTokens in SPA applications?

    I'm using something like this at the ConfigureAuth method. but just seems so expensive per request!

    app.Use((context, nextModule) =>

               {

                   var PublicClientId = "self";

                   var manager = context.Get<ApplicationUserManager>();

                   OAuthOptions = new OAuthAuthorizationServerOptions

                   {

                       TokenEndpointPath = new PathString("/Token"),

                       Provider = new ApplicationOAuthProvider(PublicClientId, manager),

                       AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),

                       AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),

                       AllowInsecureHttp = true

                   };

                   return nextModule();

               });

  • I also would like clarification on how to tie in this middleware to the app.UseOAuthBearerTokens method. I posted this question on stackoverflow but don't have an answer:

    stackoverflow.com/.../example-of-using-asp-net-identity-2-0-usermanagerfactory-with-useoauthbearertoke

  • Do you know that .NET and web development with Visual Studio

  • @Bas you can do the same for RoleManager. You will have to create an instance of RoleManager in ConfigureAuth and add it to the OWIN context so you can get it from the OWIN Context in your controller

  • @Ditto I replied to your StackOverflow post. Please check

  • What about Dispose created objects? I added breakpoint in ApplicationUserManager but it looks that it never occurs. Did I miss something?

  • I am using unity as my IoC container. How can I do this but use Unity to keep track of instances instead of the owincontext.  I think I have it but I have no idea where this comes from IdentityFactoryOptions<UserManager options> and what should be in it. I am creating a factory to create my UserManager akin to what you've done in your sample project with this function public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context).

  • Great post, thanks. Hopefully more will come.

    Can someone elaborate on how to use this in WebApi as this line from the article:

    return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();

    won't work in ApiController.

    ApiController doesn't have a context property that would inherit from HttpContextBase on which the above Owin extensions are implemented.

    Btw, I've installed the latest nuget packages (WebApi 2.1, Owin 2.1, etc)

  • @EdwardM: The IdentityFactoryOptions is populated in the 'CreatePerOwinContext' extension method in the Microsoft.AspNet.Identity.Owin assembly. It basically sets the DataProtectionProvider property with the one registered with Owin. You can look at the code and see if you can inject something similar.

  • @Andrej Grobler: You can do a Request.GetOwinContext(). The extension method is defined in the Microsoft.AspNet.WebApi.Owin nuget package

  • Anyone know where the updated custom storage provider examples are for WIF 2.0.

    I see the 1.0 version here: www.asp.net/.../overview-of-custom-storage-providers-for-aspnet-identity

    and here: www.asp.net/.../implementing-a-custom-mysql-aspnet-identity-storage-provider

    Any chance of getting an updated version for WIF 2.0?  Not all of us have Entity Framework providers for our database...

  • Which namespace and assembly is IdentityFactoryOptions in? I'm trying to add this to my application. I'm using Owin 2.1.0 and Identity.Core.2.0.0 and it's not compiling.

  • I'm in agreement with EdwardM.  I've been spending a fair amount of time trying to figure out how to use this with DI, but it's really confusing having to stash things in the OWIN context and those things are just newed up (which I would never do on a real site).  OK so I can inject the UserManager and Storage Provider into my ApplicationOAuthProvider...except that this object is also just newed up on OWIN startup.  I'd really like to use this framework but this is so DI unfriendly, at least as it's laid out from the default template.  Is there any guidance out there on how to get this working properly with a DI container?  

Page 1 of 2 (16 items) 12