asp.net-mvcasp.net-mvc-5ninject.web.mvcasp.net-identity-2asp.net-mvc-controller

How to inject User Manager to Account Controller with default Identity Model in Identity 2 using Ninject


I use Ninject on a MVC 5 project with Identity 2.

For rest of data context and controllers using that I have no problems with dependency injection.

For Account controller that uses Identity 2 model I'm getting null UserManager when I try to login:

public class AccountController : Controller
{
    private ApplicationUserManager _userManager;

    public AccountController()
    {
    }

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

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

What is the proper way to inject required dependencies? I did not create a custom UserManager, it's out of the box model, ApplicationUserManager is as defined in IdentityConfig.cs under App_Start.

As a side note: I'm using Conventions Extension of Ninject:

private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind(
           x => x.FromThisAssembly()
               .SelectAllClasses()
               .BindAllInterfaces()
           );

Thanks.


Solution

  • I had the same problem working with Ninject4.0, MVC5.2.3, Identity2.0 and Owin3.0.1, here you should do for working everything properly.

    1. First of all you should get Ninject.Web.Common.OwinHost from NuGet, because if you working with Owin, you want to use NinjectMiddleware.

          public partial class StartUp
          { 
               private IKernel kernel = null;
               public void Configuration(IAppBuilder app)
               {
                  kernel = CreateKernel();
                  app.UseNinjectMiddleware(() => kernel);
                  ConfigureAuth(app);
               }
      
               public IKernel CreateKernel()
               {
                  var kernel = new StandardKernel();
                  try
                  {
      
                     // TODO: Put any other injection which are required.
                     RegisterServices(kernel);
                     return kernel;
                  }
                  catch
                  {
                    kernel.Dispose();
                    throw;
                  }
               }
            }
      
    2. As you can see, we have a method for injecting all services that we want, in this case we must inject ApplicationUserManager, IUserStore and DbContext. So for RegisterServices in Startup class, we have :

           private static void RegisterServices(IKernel kernel) 
           {
      
              kernel.Bind<DbContext>().To<ApplicationDbContext>();
              kernel.Bind<IUserStore<User, long>>().To<UserStore<User, Role, long, UserLogin, UserRole, UserClaim>>();
      
              kernel.Bind<ApplicationUserManager>().ToSelf();
      
          }
      

      Note: I use long insted of string as a type of all keys on Identity, but using a defualt (string as key) should be the same.

    3. In StartUp.Auth.cs file that contains partial of StartUp class we should change ConfigureAuth method to this :

           internal static IDataProtectionProvider DataProtectionProvider
           { get; private set; }
      
           public void ConfigureAuth(IAppBuilder app)
           {
           DataProtectionProvider = app.GetDataProtectionProvider();
          //app.CreatePerOwinContext<ApplicationUserManager(ApplicationUserManager.Create)
      
           app.CreatePerOwinContext<ApplicationUserManager>(
           (option, context) => {
                  var kernl = context.Get<IKernel>();
      
                return kernel.Get<ApplicationUserManager>();
      
              });
      
               //rest of the code 
         }
      

      Note: we get ApplicationUserManager from owin before but now we get it from Ninject kernel.please notice we create a internal static property for DataProtectionProvider and set it from appBuilder, we're going to use this property in IdentityConfig/ApplicationUserManager.(see it later)

    4. Now we must change ApplicationUserManager, we remove code from Create method to constructor with just one dependency with IUserStore, here is the final look:

             public class ApplicationUserManager : UserManager<User,long>
             {
              public ApplicationUserManager(IUserStore<User,long> store)
                 :base(store)
                {
      
      
                this.UserValidator = new UserValidator<User, long>(this)
                  {
                     AllowOnlyAlphanumericUserNames = false,
                     RequireUniqueEmail = true
                   };
               // Configure validation logic for passwords
               this.PasswordValidator = new PasswordValidator
                   {
                      RequiredLength = 6,
                      RequireNonLetterOrDigit = true,
                      RequireDigit = true,
                      RequireLowercase = true,
                      RequireUppercase = true,
                   };
      
                var dataProtectionProvider = Startup.DataProtectionProvider;
      
               // this is unchanged
               if (dataProtectionProvider != null)
               {
                  IDataProtector dataProtector = 
                        dataProtectionProvider.Create("ASP.NET Identity");
      
                  this.UserTokenProvider = 
                    new DataProtectorTokenProvider<User,long>(dataProtector);
               }
            }
         }
      
    5. at last we can use ApplicationUserManager in our Accountcontroller's constructor like this:

       public class AccountController : ApiController
       {
           private ApplicationUserManager UserManager ;
           public AccountController(ApplicationUserManager userManager){
      
                  UserManager = userManager;
           }
          // all apis come here
      
        }