18

I'm using Unity successfully for all regular constructor injection such as repositories etc., but I can't get it working with the ASP.NET Identity classes. The setup is this:

public class AccountController : ApiController
{
    private UserManager<ApplicationUser> _userManager { get; set; }

    public AccountController(UserManager<ApplicationUser> userManager)
    {
        if (userManager == null) { throw new ArgumentNullException("userManager"); }
        _userManager = userManager;
    }

    // ...
}

with these configs for Unity:

unity.RegisterType<AccountController>();
unity.RegisterType<UserManager<ApplicationUser>>(new HierarchicalLifetimeManager());
unity.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new HierarchicalLifetimeManager());

That's the same as other posts here for Autofac, Ninject e.g., but it doesn't work in my case. The error message is:

An error occurred when trying to create a controller of type 'AccountController'. Make sure that the controller has a parameterless public constructor. Manual creation works of course:

public AccountController()
    : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>("Mongo")))
{
}

What's wrong?

UPDATE

As suggested by @emodendroket, shortening the code to this does the trick. No need for the Unity.Mvc package.

unity.RegisterType<IUserStore<IdentityUser>, 
  MyCustomUserStore>(new HierarchicalLifetimeManager());

and

public AccountController(UserManager<IdentityUser> _userManager,
  IAccountRepository _account)
{
    // ...
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Benjamin E.
  • 5,042
  • 5
  • 38
  • 65
  • Mvc and web api uses different interfaces for DI. Nuget the latest Unity WebApi package from Microsoft P&P – Aron Feb 21 '14 at 07:24
  • Sure? I can only see differences in the "bootstrapper" packages and 3rd party libs, not the Unity package itself. – Benjamin E. Feb 21 '14 at 07:50
  • Do you not get the inner exception? – Aron Feb 21 '14 at 09:00
  • 1
    Install the Unity.Mvc package. Also, you don't need to register the controller. That message seems to suggest that you're still using the default controller factory, which Unity.Mvc should help with. – Casey Mar 25 '14 at 19:46
  • If you've just installed the Unity MVC package and have trouble with the ASP.NET Identity Accounts controller, see here: http://stackoverflow.com/questions/20023065/how-to-add-mvc-5-authentication-to-unity-ioc – Mark Sowul Oct 19 '15 at 22:02

4 Answers4

21

You also need to resolve the UserManager. The following is an example how you could do it with the UserManager and the RoleManager. In this sample I use the regular Unity 3 package instead of one of the derivates or bootstrappers (had some problems with them in the past).

AccountController

private readonly UserManager<ApplicationUser> _userManager;

private readonly RoleManager<IdentityRole> _roleManager;

public AccountController(IUserStore<ApplicationUser> userStore, IRoleStore<IdentityRole> roleStore)
{
  _userManager = new UserManager<ApplicationUser>(userStore);
  _roleManager = new RoleManager<IdentityRole>(roleStore);
}

Unity Bootstrapper

var accountInjectionConstructor = new InjectionConstructor(new IdentitySampleDbModelContext(configurationStore));
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(accountInjectionConstructor);
container.RegisterType<IRoleStore<IdentityRole>, RoleStore<IdentityRole>>(accountInjectionConstructor);
Horizon_Net
  • 5,959
  • 4
  • 31
  • 34
  • Thanks, only injecting the UserStore works. But why would I not try to have Unity inject the UserManager instance as well? Because it's anyway part of the framework and no code I have to test/replace? – Benjamin E. Feb 21 '14 at 11:02
  • 1
    Not necessary. You can actually inject these things. – Casey Mar 25 '14 at 19:45
  • 1
    Could you elaborate on the congfigurationStore you're passing in? – Mastro Jun 02 '14 at 21:56
  • Oh, missed it that I paste it in. The configurationStore is an implementation I use to determine if I run locally and pass in my local configuration file or if I run on Azure (most work I do is Azure-related) and use the Azure configuration file. You can replace the configurationStore with the connection to your database. – Horizon_Net Jun 03 '14 at 07:51
  • 3
    I am using identical code to you and the UserStore is registered fine, however it will not compile the RoleStore registration. Error = The type 'Microsoft.AspNet.Identity.EntityFramework.RoleStore' cannot be used as type parameter 'TTo' in the generic type or method 'Microsoft.Practices.Unity.UnityContainerExtensions.RegisterType(Microsoft.Practices.Unity.IUnityContainer, params Microsoft.Practices.Unity.InjectionMember[])'. – Mike Dymond Jan 17 '15 at 00:07
  • 5
    @MikeDymond I believe it should be container.RegisterType, RoleStore>(accountInjectionConstructor). The string part is missing – Eitan K Mar 03 '16 at 19:32
15

As this blog post from enterpriseframework.com says:

First, add the Unity Bootstrapper for ASP.NET MVC Nuget package.

  1. In your Visual Studio "Solution Explorer" > right click on your Web project's "References" node > click "Manage NuGet Packages".

  2. From the left menu, choose Online > All

  3. In the upper right search box > Search Online (Ctrl + E) > type "Unity bootstrapper for ASP.NET MVC".
  4. Select "Unity Bootstrapper for ASP.NET MVC" and choose Install.
  5. Click Close after install completes

Then Modify your-Web-project/App_Start/UnityConfig.cs file and update the using statements as follows:

    using System;
    using System.Data.Entity;
    using Microsoft.AspNet.Identity;
    using Microsoft.AspNet.Identity.EntityFramework;
    using Microsoft.Practices.Unity;
    using Microsoft.Practices.Unity.Configuration;
    using MicrosoftIdentity.Controllers;
    using MicrosoftIdentity.Models;

Finally, in the same file, update RegisterTypes method as below:

        public static void RegisterTypes(IUnityContainer container)
        {
            // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
            // container.LoadConfiguration();

            // TODO: Register your types here
            container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>();
            container.RegisterType<UserManager<ApplicationUser>>();
            container.RegisterType<DbContext, ApplicationDbContext>();
            container.RegisterType<ApplicationUserManager>();
            container.RegisterType<AccountController>(new InjectionConstructor());
        }

HTH

Kamran
  • 782
  • 10
  • 35
-1
Install-Package Unity.AspNet.WebApi

You need to register Unity under the HttpConfiguration.DependencyResolver property. This allows WebApi to know that it needs to use Unity rather than reflection to instanciate your controllers.

The easiest way to do this is with the above nuget package.

Aron
  • 15,464
  • 3
  • 31
  • 64
  • Unity.AspNet.WebApi is just scaffolding for Unity plus it has an implementation of `IDependencyResolver`. Unity is working fine, it's just not working for the specific classes of ASP.NET Identity. I suspect the problem is in `UserManager`, which I'm probably trying to register in a wrong way. – Benjamin E. Feb 21 '14 at 08:40
-1

Replace this property in the AccountController

public ApplicationUserManager UserManager
{
    get
    { 
        _userManager = new ApplicationUserManager(
                          new UserStore<ApplicationUser>(new ApplicationDbContext()));
        return _userManager ??
               Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
    }
    private set
    {
        _userManager = value;
    }
}
theB
  • 6,450
  • 1
  • 28
  • 38
  • Please consider adding some explanation as to why this answer is correct, and better than the other answers. – theB Sep 22 '15 at 23:01