Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The current types, IUserStore<ApplicationUser> and DbConnection, are respectively an interface and abstract class and cannot be constructed

If I surf to http://localhost:58472/Account/Register I've this exception

System.InvalidOperationException: The current type, IUserStore<ApplicationUser>, is an interface and cannot be constructed. Are you missing a type mapping?

Here is my code:

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager(IUserStore<ApplicationUser> store)
        : base(store)
    { }

    public static ApplicationUserManager Create(
        IdentityFactoryOptions<ApplicationUserManager> options, 
        IOwinContext context) 
    {
        var manager = new ApplicationUserManager(
            new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>())
        );

        // other code
        return manager;   
    }
}

and here is the code into the controller:

[Authorize]
public class AccountController : Controller
{
    private ApplicationSignInManager _signInManager;
    private ApplicationUserManager _userManager;

    public AccountController()
    {
    }

    public AccountController(
        ApplicationUserManager userManager,
        ApplicationSignInManager signInManager)
    {
        UserManager = userManager;
        SignInManager = signInManager;
    }

    public ApplicationSignInManager SignInManager
    {
        get
        {
            return _signInManager ?? 
                HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
        }
        private set
        {
            _signInManager = value;
        }
    }

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

    [HttpGet]
    [AllowAnonymous]
    public ActionResult Login(string returnUrl)
    {
        ViewBag.ReturnUrl = returnUrl;
        return View();
    }
}

So you can see if you read my code, I've nothing changed to the original code when you create a new MVC project, but I've got the error above. What did I wrong?

I've well made a new controller named ProfileController with the same code as in my second code block but without the ApplicationSignInManager because I don't need that.

I also use an Unity container to register and manage the services. Here is the code:

public static class UnityConfig
{
    public static void RegisterComponents()
    {
        var container = new UnityContainer();

        container.RegisterType<IGenericRepo<Category>, GenericRepo<Category>>();
        container.RegisterType<ICategoryService, CategoryService>();
        //container.RegisterType<IUser, ApplicationUser>(); 

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
    }
}

If I uncomment the line in code above, there aren't any difference when I run the site.


Update:

By a comment by @Jay I've added this code in the Unity manager.

container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>();

Now I've got this exception:

System.InvalidOperationException: The current type, System.Data.Common.DbConnection, is an abstract class and cannot be constructed. Are you missing a type mapping?

Here is some information from the stack trace:

  1. InvalidOperationException

    An error occurred when trying to create a controller of type AccountController. Make sure that the controller has a parameterless public constructor.

    Yes, I've got a paramaterless public constructor.

  2. ResolutionFailedException

    Resolution of the dependency failed, type = "AccountController", name = "(none)".

So I've added this line in the Unity manager:

container.RegisterType<IDbConnection, DbConnection>();

But I've still have the same exception.

The current type, System.Data.Common.DbConnection...


Update:

By a comment by @RandyLevy I've tried this, helping by this question Configure Unity DI for ASP.NET Identity:

  1. Adding this to the AccountController:

    // two fields added
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<IdentityRole> _roleManager;
    
    // constructor added
    public AccountController(
        IUserStore<ApplicationUser> userStore, 
        IRoleStore<IdentityRole> roleStore, 
        ApplicationSignInManager signInManager)
    {
        _userManager = new UserManager<ApplicationUser>(userStore);
        _roleManager = new RoleManager<IdentityRole>(roleStore);
        SignInManager = signInManager; // I need this
    }
    
    public ApplicationSignInManager SignInManager // I need this
    {
        get
        {
            return _signInManager ?? 
                HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
        }
        private set
        {
            _signInManager = value;
        }
    }
    
    public UserManager<ApplicationUser> UserManager // replace by other property 
                                                    // type of ApplicationUserManager 
    {
        get
        {
            return _userManager ?? 
                HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        //private set // comment this because _usermanager is readonly.
        //{
        //    _userManager = value;
        //}
    }
    
    //public ApplicationUserManager UserManager // replaced by the property type of 
    //                                          // UserManager<ApplicationUser>
    //{
    //    get
    //    {
    //        return _userManager ?? 
    //            HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
    //    }
    //    private set
    //    {
    //        _userManager = value;
    //    }
    //}
    
  2. Adding this into UnityManager:

    InjectionConstructor accountInjectionConstructor = 
        new InjectionConstructor(new ApplicationDbContext());
    
    container.RegisterType<AccountController>();
    container.RegisterType<IController, Controller>();
    
    container.RegisterType
        <IRoleStore<IdentityRole>, RoleStore<IdentityRole>>
        (accountInjectionConstructor); // on this line
    
    container.RegisterType
        <IUserStore<ApplicationUser>, UserStore<ApplicationUser>>
        (accountInjectionConstructor);
    

But I've got this error (no run time exception) on the line with the comment:

The type RoleStore<IdentityRole> cannot be used as type parameter TTo in the generic type or method below:

UnityContainerExtensions.RegisterType<TFrom, TTo>
    (IUnityContainer, params InjectionMember[])

There is no implicit reference conversion from RoleStore<IdentityRole> to IRoleStore<IdentityRole>.

like image 860
H. Pauwelyn Avatar asked Feb 17 '16 15:02

H. Pauwelyn


2 Answers

Finally I've found a solution for my problem. I've add this code into the Unity manager.

container.RegisterType<DbContext, ApplicationDbContext>(new HierarchicalLifetimeManager());
container.RegisterType<UserManager<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<AccountController>(new InjectionConstructor());
like image 88
H. Pauwelyn Avatar answered Nov 14 '22 23:11

H. Pauwelyn


Update for H. Pauwelyn answer. The original problem for this is that Unity tries to call the constructor with two parameters.

public AccountController(
    ApplicationUserManager userManager,
    ApplicationSignInManager signInManager)
{
    UserManager = userManager;
    SignInManager = signInManager;
}

The following line will tell Unity to call the parameterless constructor instead and won't need anything else. This worked for me.

container.RegisterType<AccountController>(new InjectionConstructor());
like image 22
Ogglas Avatar answered Nov 15 '22 01:11

Ogglas