Simple Injector Identity UserManager<AppUser, Int32> 注册错误

Simple Injector Identity UserManager<AppUser, Int32> Registration Error

我正在关注 Onion Architecture 并使用 Identity Framework。在我的核心项目中,我有:

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

在我的Architecture.Repository中,我有

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;
     }
}

在我的依赖项解析项目中,我有:

[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)
            };
        }
    }
}

container.Verify() 上,我收到以下错误:

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.

有人可以指导我做错了什么以及我需要做些什么来纠正它吗?

异常消息说:

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.

异常提示您应该为IUserStore<AppUser, int>注册,因为UserManager<AppUser, int>依赖于此。例如,您可以进行以下注册:

// 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);

但是,根据 this article,您不应该自动连接框架类型,例如 UserManager<TUser, TKey>,而是通过自己创建此类类型来使用手动注册。例如:

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

最好不要在核心应用程序中直接使用外部库(例如 UserManager<TUser, TKey>)中的类型。特别是因为您正在练习洋葱架构。此架构提倡 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(五项 SOLID 原则之一)描述。

因此,与其让您的 UserRepository 依赖于 UserManager<TUser, TKey> 之类的框架类型,不如让它依赖于具有 very narrowly defined and single responsibility 的自定义定义的抽象。此抽象的适配器可以依次使用 UserManager<TUser, TKey>.

根据 UserRepository 的作用,您甚至可以将此 UserRepository 本身视为适配器。在这种情况下,让 UserRepository 直接依赖于 UserManager<TUser, TKey> 就可以了。在那种情况下,将 UserManager<TUser, TKey> 隐藏在额外的抽象之后只会导致 extra/needless 抽象层。

但是尽管如此,适配器不仅可以直接依赖于 UserManager<TUser, TKey>,还可以简单地控制 UserManager<TUser, TKey> 本身的创建和销毁。换句话说,您的 UserRepository 可以如下所示:

// 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;
         }
     }
}

在 Simple Injector 讨论中,有一个 interesting description about how to work with Identity and Visual Studio's default template. And here 是一个关于身份的 Whosebug q/a,您可能也会觉得有趣。