4

I am following Onion Architecture and using Identity Framework. In my Core project, I have:

public interface IUserRepository : IDisposable
{
     // Repository methods.......
}

In my Architecture.Repository, I have

public class UserRepository : IUserRepository
{
     // This is Identity UserManager
     private readonly UserManager<AppUser, int> _userManager;   
     private readonly IAuthenticationManager _authenticationManager;
     private bool _disposed;

     public UserRepository(UserManager<User, int> userManager,
         IAuthenticationManager authenticationManager)
     {
          _userManager = userManager;
          _authenticationManager = authenticationManager;
     }
}

In my dependency resolution project, I have:

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(IocConfig),
    "RegisterDependencies")]
namespace AdShad.Infrastructure.DependencyResolution
{
    public class IocConfig
    {
        public static void RegisterDependencies()
        {
            var container = new Container();
            container.RegisterWebApiRequest<IUnitOfWork, UnitOfWork>();
            container.RegisterWebApiRequest<IUserRepository, UserRepository>();

            container.RegisterManyForOpenGeneric(typeof(IRepository<>),
                typeof(BaseRepository<>).Assembly);
            container.RegisterWebApiRequest<IEntitiesContext, MyContext>();

            container.RegisterWebApiRequest(
                () => HttpContext.Current.GetOwinContext().Authentication);

            container.Verify();

            HttpConfiguration config = new HttpConfiguration
            {
                DependencyResolver = 
                    new SimpleInjectorWebApiDependencyResolver(container)
            };
        }
    }
}

On container.Verify(), I am getting the following error:

An exception of type 'System.InvalidOperationException' occurred in SimpleInjector.dll but was not handled in user code

Additional information: The configuration is invalid. Creating the instance for type IUserRepository failed. The registered delegate for type IUserRepository threw an exception. No registration for type UserManager could be found and an implicit registration could not be made. The constructor of type UserManager contains the parameter of type IUserStore with name 'store' that is not registered. Please ensure IUserStore is registered, or change the constructor of UserManager.

Can someone guide me what I am doing wrong and what I need to do to correct it?

Steven
  • 166,672
  • 24
  • 332
  • 435
Usman Khalid
  • 3,032
  • 9
  • 41
  • 66
  • But you don't have registration `UserManager` in the container... and exception is saying about it, that `UserManager` constuctor requires `IUserStore` parameter so SimpleInjector can't create it. You need to register `IUserStore` in the container or delegate for `UserManager` class – Sergey Litvinov Jun 02 '15 at 17:50
  • But I don't have any IUserStore and no concrete class for that interface, how can I register? – Usman Khalid Jun 02 '15 at 18:15
  • @UsmanKhalid you'll need to pick a `UserStore` implementation or create your own ([here](http://www.asp.net/identity/overview/getting-started/adding-aspnet-identity-to-an-empty-or-existing-web-forms-project), [here](http://www.asp.net/identity/overview/extensibility/overview-of-custom-storage-providers-for-aspnet-identity) etc.) – qujck Jun 02 '15 at 18:32

1 Answers1

9

The exception message says:

The constructor of type UserManager<AppUser, int> contains the parameter of type IUserStore with name 'store' that is not registered. Please ensure IUserStore<AppUser, int> is registered, or change the constructor of UserManager.

The exception suggests that you should make a registration for IUserStore<AppUser, int>, because the UserManager<AppUser, int> depends on this. So you could for instance make the following registration:

// UserStore<TUser> is defined in Microsoft.AspNet.Identity.EntityFramework.
// Do note that UserStore<TUser> implements IUserStore<TUser, string>, so
// this Entity Framework provider requires a string. If you need int, you
// might have your own store and need to build your own IUserStore implemenation.
container.Register<IUserStore<AppUser, string>>(
    () => new UserStore<AppUser>>(),
    Lifestyle.Scoped);

However, according to this article, you should not auto-wire framework types such as UserManager<TUser, TKey>, but use manual registration instead by creating such type yourself. For instance:

container.Register<UserManager<AppUser, string>>(
    () => new UserManager<AppUser, string>(new UserStore<AppUser>()),
    Lifestyle.Scoped);

It would be even better to refrain from using types from external libraries (such as the UserManager<TUser, TKey>) directly in your core application. Especially since you are practicing the Onion architecture. This architecture promotes SOLID principles and describes the concept of ports and adapters. A port is an abstraction defined by your application that allows a gateway into some external domain or library. An adapter is an implementation of such abstraction that actually connects to this external domain or library. This is exactly what the Dependency Inversion Principle (one of the five SOLID principles) describes.

So instead of letting your UserRepository depend on a framework type such as UserManager<TUser, TKey>, let it depend on a customly defined abstraction, with a very narrowly defined and single responsibility. The adapter for this abstraction can on its turn use UserManager<TUser, TKey>.

Depending on what UserRepository does, you might even consider this UserRepository itself an adapter. In this case, letting UserRepository depend directly on UserManager<TUser, TKey> is fine. In that case, hiding the UserManager<TUser, TKey> behind an extra abstraction just causes an extra/needless layer of abstraction.

But nonetheless, the adapter can not only directly depend on UserManager<TUser, TKey>, but it can simply control the creation and destruction of UserManager<TUser, TKey> itself. In other words, your UserRepository can look as follows:

// NOTE: Do not let IUserRepository implement IDisposable. This violates
// the Dependency Inversion Principle.
// NOTE2: It's very unlikely that UserRepository itself needs any disposal.
public class UserRepository : IUserRepository
{
    // This is Identity UserManager
    private readonly IAuthenticationManager _authenticationManager;

     public UserRepository(IAuthenticationManager authenticationManager)
     {
          _authenticationManager = authenticationManager;
     }

     public void Delete(AppUser user) {
         // Here we create and dispose the UserManager during the execution
         // of this method.
         using (manager = new UserManager<AppUser, string>(
             new UserStore<AppUser>())) {
             manager.DeleteAsync(user).Result;
         }
     }
}

In the Simple Injector discussions there is an interesting description about how to work with Identity and Visual Studio's default template. And here is a Stackoverflow q/a about Identity that you might find interesting as well.

Steven
  • 166,672
  • 24
  • 332
  • 435
  • Thank you very much. That's a lot of help. Actually I am totally new to onion architecture and simple injector. There are some restriction from client side that I have to use Onion Architecture using db first approach and with ASP.NET Identity framework. I am not finding enough help over the internet for my requirement. But anyhow thanks a lot. I will reach all these articles and try to implement them. – Usman Khalid Jun 02 '15 at 18:53
  • I don't know what you are trying to say here : "you should not auto-wire framework types such as UserManager, but use manual registration instead by creating such type yourself". Are you trying to say I should not customize Identity UserManager? – Usman Khalid Jun 03 '15 at 17:17
  • @UsmanKhalid: no, auto-wiring is the process where the container selects the right constructor and automatically injects the right dependencies. Manual wiring is where your code calls that constructor. This is what my examples do. They call the ctor inside a lambda expression. – Steven Jun 03 '15 at 17:33