Search code examples
asp.netowinkatana

What is the purpose of the extension method CreatePerOwinContext in OWIN implementation by Microsoft


I am a newbie in ASP.NET, and currently learning ASP.NET Identity. I know it's built on top of OWIN implementation by Microsoft, and I am also still learning that too. So, I came across the extension method CreatePerOwinContext in the Owin startup code, and I don't see a clear purpose of using it. Is it some kind of dependency injection container? What is the real purpose of the method? In what case it should be applied?


Solution

  • CreatePerOwinContext registers a static callback which your application will use to get back a new instance of a specified type.
    This callback will be called once per request and will store the object/objects in OwinContext so that you will be able to use them throughout the application.

    Let's say you have defined your own implementation of IdentityDbContext:

    public class ApplicationDatabaseContext : IdentityDbContext<MyApplicationUser, MyRole, Guid, MyUserLogin, MyUserRole, MyUserClaim>
    {
        public ApplicationDatabaseContext() : base("<connection string>")
        {
        }
    
        public static ApplicationDatabaseContext Create()
        {
            return new ApplicationDatabaseContext();
        }
    
            protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
            {
            base.OnModelCreating(modelBuilder);
    
            // Customize your table creation here.
    
                #region USERS - INFOS
    
            modelBuilder.Entity<UserInfo>()
                .Property(p => p.FirstName)
                .HasColumnType("varchar")
                .HasMaxLength(70);
    
            modelBuilder.Entity<UserInfo>()
                .Property(p => p.LastName)
                .HasColumnType("varchar")
                .HasMaxLength(70);
    
            modelBuilder.Entity<UserInfo>()
                .Property(p => p.Address)
                .HasColumnType("varchar")
                .HasMaxLength(100);
    
            modelBuilder.Entity<UserInfo>()
                .Property(p => p.City)
                .HasColumnType("varchar")
                .HasMaxLength(100);
    
            modelBuilder.Entity<UserInfo>()
                .ToTable("UsersInfo");
    
            #endregion  
            }
    
            public DbSet<UserInfo> UsersInfo { get; set; }
    }
    

    and your implementation of UserManager:

    public class ApplicationUserManager : UserManager<MyApplicationUser, Guid>
    {
        public ApplicationUserManager(IUserStore<MyApplicationUser, Guid> store) : base(store)
            {
            }
    
            public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
            {
                var manager = new ApplicationUserManager(new MyUserStore(context.Get<ApplicationDatabaseContext>()));
    
                manager.UserValidator = new UserValidator<MyApplicationUser, Guid>(manager)
                {
                    AllowOnlyAlphanumericUserNames = false,
                    RequireUniqueEmail = true
                };
    
                manager.PasswordValidator = new PasswordValidator()
                {
                    RequiredLength = 6,
                    RequireNonLetterOrDigit = false,    
                    // RequireDigit = true,
                    RequireLowercase = false,
                    RequireUppercase = false,
                };
    
                var dataProtectionProvider = options.DataProtectionProvider;
    
                if (dataProtectionProvider != null)
                {
                    manager.UserTokenProvider = new DataProtectorTokenProvider<MyApplicationUser, Guid>(dataProtectionProvider.Create("PasswordReset"));
                }
    
                return (manager);
            }
    }
    

    In your Owin Startup you will register the callback:

    // IAppBuilder app
    
    app.CreatePerOwinContext<ApplicationDatabaseContext>(ApplicationDatabaseContext.Create);
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
    

    which will call the static method:

    public static ApplicationDatabaseContext Create()
    {
        return new ApplicationDatabaseContext();
    }
    

    and

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        ...
    }
    

    Now you will be able to access your database context and user manager in a simple straightforward way:

    ApplicationDatabaseContext dbContext = context.OwinContext.Get<ApplicationDatabaseContext>();
    ApplicationUserManager userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
    

    In your ApiController (if you're using WebApi):

    IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
    ApplicationUserManager applicationUserManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();