10

i get the following exception when trying to configure Unity using Unity.Mvc5 with an MVC 5 application using Identity 2.0 and the Identity 2.0 Samples boilerplate. i have read this SO Configure Unity DI for ASP.NET Identity and i'm still not clear on what i'm missing. What am i doing wrong here?

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

[ResolutionFailedException: Resolution of the dependency failed, type = "myApp.Web.Controllers.AccountController", name = "(none)". Exception occurred while: while resolving.

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

At the time of the exception, the container was:

Resolving myApp.Web.Controllers.AccountController,(none) Resolving parameter "userManager" of constructor myApp.Web.Controllers.AccountController(myApp.Web.Models.ApplicationUserManager userManager) Resolving myApp.Web.Models.ApplicationUserManager,(none) Resolving parameter "store" of constructor myApp.Web.Models.ApplicationUserManager(Microsoft.AspNet.Identity.IUserStore1[[myApp.Web.DAL.Profiles.ApplicationUser, myApp.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] store) Resolving Microsoft.AspNet.Identity.EntityFramework.UserStore1[myApp.Web.DAL.Profiles.ApplicationUser],(none) (mapped from Microsoft.AspNet.Identity.IUserStore1[myApp.Web.DAL.Profiles.ApplicationUser], (none)) Resolving parameter "context" of constructor Microsoft.AspNet.Identity.EntityFramework.UserStore1[[myApp.Web.DAL.Profiles.ApplicationUser, myApp.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]](System.Data.Entity.DbContext context) Resolving System.Data.Entity.DbContext,(none) Resolving parameter "existingConnection" of constructor System.Data.Entity.DbContext(System.Data.Common.DbConnection existingConnection, System.Data.Entity.Infrastructure.DbCompiledModel model, System.Boolean contextOwnsConnection) Resolving System.Data.Common.DbConnection,(none)

account controller as i have modified it

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

 private ApplicationUserManager _userManager;

containers i have registered

container.RegisterType<ApplicationUserManager>(new HierarchicalLifetimeManager());
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new HierarchicalLifetimeManager());
Community
  • 1
  • 1
Michael
  • 1,022
  • 1
  • 11
  • 28

2 Answers2

22

I see you found a solution, but I think I have a simpler one.

You're using Entity Framework, right? So your application almost certainly has something inheriting from DbContext (probably inheriting from IdentityContext<TUser>, which in turn inherits from DbContext in this case). In the default template it's ApplicationDbContext.

In your composition root you can just add container.RegisterType<DbContext, ApplicationDbContext>(new HierarchicalLifetimeManager()); (obviously edit this if yours isn't called ApplicationDbContext).

Casey
  • 3,307
  • 1
  • 26
  • 41
  • i will give this a try. this certainly would be much simpler than having to create a custom userstore when i'm not doing anything different. – Michael Apr 23 '14 at 17:27
  • Right, yeah. I'm pretty sure, by the message, that it's failing to resolve DbContext, which classes like UserManager want a copy of. You could also use an InjectionFactory if you were so inclined. – Casey Apr 23 '14 at 18:11
  • is it not better to use PerRequestLifetimeManager instead of HierarchicalLifetimeManager ? – Dragouf May 03 '14 at 05:07
  • Yes, probably, if you have it installed in your project. I was sticking with what was in the sample. It's also possible to do something similar with HLM and child containers, I believe. – Casey May 04 '14 at 03:26
  • What happens if I have 2 DbContexts? One for Identity stuff, Let's call it IdentityDb and another for business entities, BusinessDb. – Bogac Aug 24 '14 at 13:03
  • @Bogac You have two choices -- either you can specify in your classes which one you're looking for and register both as their actual types, or you can register two versions of DbContext with different string "keys" and then specify in your Unity configuration which one you'd like. If that doesn't answer your question I'd suggest posting a separate question with more details about what you're doing because the comments aren't an ideal format to get into the weeds. – Casey Aug 24 '14 at 23:13
  • I'm trying to add a DI to my Entities context and have the following line in my `UnityConfig.cs` `container.RegisterType(new HierarchicalLifetimeManager());` But I'm still getting the error discussed here. Any ideas? :-/ – Felipe Correa Aug 24 '15 at 16:15
  • @Casey Can you take a look at the comment above please, I forgot to mention you when I asked a while ago. Thanks! – Felipe Correa Aug 24 '15 at 19:30
  • @FelipeCorrea Well you can get this same error for any component. Maybe you should post your own question with a full stack trace. – Casey Aug 25 '15 at 01:17
  • @Casey I solved it. My `EntitiesDataContext` had several constructors and I didn't knew that Unity selected the constructor with more parameters by default. I had to call it like this to fix it: `container.RegisterType(new PerRequestLifetimeManager(), new InjectionConstructor());` The `InjectionConstructor` made the difference :) – Felipe Correa Aug 25 '15 at 01:19
2

ok i figured it out. i think. i created my own userstore class and plugged it in. this was helpful somewhat. http://odetocode.com/blogs/scott/archive/2014/01/20/implementing-asp-net-identity.aspx

unity config

container.RegisterType<ApplicationDbContext>(new HierarchicalLifetimeManager());
container.RegisterType<IUserStore<ApplicationUser>, bcUserStore>(new HierarchicalLifetimeManager());

user manager

public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
   var manager = new ApplicationUserManager(new bcUserStore(context.Get<ApplicationDbContext>()));
// other code that's not relevant
}

user store

public class bcUserStore : IUserStore<ApplicationUser>
{
    private IDbSet<ApplicationUser> _users;
    private ApplicationDbContext _context;
    public bcUserStore(ApplicationDbContext context)
    {
        _users = context.Users;
        _context = context;
    }
    public System.Threading.Tasks.Task CreateAsync(ApplicationUser user)
    {
        user.Id = Guid.NewGuid().ToString();
        _users.Add(user);
        return _context.SaveChangesAsync();
    }

    public System.Threading.Tasks.Task DeleteAsync(ApplicationUser user)
    {
        _users.Remove(user);
        return _context.SaveChangesAsync();
    }

    public System.Threading.Tasks.Task<ApplicationUser> FindByIdAsync(string userId)
    {
        return _users.FirstOrDefaultAsync(x => x.Id == userId);
    }

    public System.Threading.Tasks.Task<ApplicationUser> FindByNameAsync(string userName)
    {
        return _users.FirstOrDefaultAsync(x => x.UserName == userName);
    }

    public System.Threading.Tasks.Task UpdateAsync(ApplicationUser user)
    {
        var current = _users.Find(user.Id);
        _context.Entry<ApplicationUser>(current).CurrentValues.SetValues(user);
        return _context.SaveChangesAsync();
    }

    public void Dispose()
    {
        _users = null;
        _context.Dispose();
    }
}
Michael
  • 1,022
  • 1
  • 11
  • 28