简单注入器身份 UserManager<AppUser, Int32> 注册错误

4
我正在遵循洋葱架构并使用身份验证框架。在我的核心项目中,我有:

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()时,我遇到了以下错误:

发生了类型为“System.InvalidOperationException”的异常,但在用户代码中未处理。

额外的信息:配置无效。创建IUserRepository类型的实例失败。IUserRepository类型的注册委托引发了异常。找不到UserManager类型的注册,并且不能进行隐式注册。UserManager类型的构造函数包含名称为'store'的IUserStore类型参数,该参数未注册。请确保已注册IUserStore,或更改UserManager的构造函数。

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

但是容器中没有注册UserManager...异常提示了这一点,即UserManager构造函数需要IUserStore参数,因此SimpleInjector无法创建它。您需要在容器中注册IUserStore或为UserManager类委托。 - Sergey Litvinov
但是我没有任何IUserStore和该接口的具体类,我怎么注册呢? - Usman Khalid
@UsmanKhalid,你需要选择一个UserStore实现或创建自己的实现(这里这里等)。 - qujck
1个回答

9
异常信息如下:
构造函数类型UserManager<AppUser, int>包含名为“store”的IUserStore类型参数,但未注册。请确保已注册IUserStore<AppUser, int>,或更改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);

然而,根据这篇文章,你不应该自动装配框架类型,比如UserManager<TUser, TKey>,而是应该通过手动注册来创建这种类型。例如:

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

最好不要直接在核心应用程序中使用外部库中的类型(比如 UserManager<TUser, TKey>)。特别是因为你正在使用洋葱架构。这种架构提倡SOLID原则,并描述了端口和适配器的概念。端口是由您的应用程序定义的抽象,允许进入某个外部域或库。适配器是这种抽象的实现,实际上连接到这个外部域或库。这正是依赖反转原则(SOLID原则之一)所描述的。
因此,不要让您的UserRepository依赖于像UserManager<TUser,TKey>这样的框架类型,而是让它依赖于一个自定义定义的抽象,具有非常狭义的单一职责。该抽象的适配器可以反过来使用UserManager<TUser,TKey>
根据UserRepository的功能,您甚至可以考虑将其本身视为适配器。在这种情况下,让UserRepository直接依赖于UserManager<TUser,TKey>是可以的。在这种情况下,将UserManager<TUser,TKey>隐藏在额外的抽象层后面只会导致额外/不必要的抽象层。

然而,适配器不仅可以直接依赖于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的讨论中,有一个有趣的描述,关于如何使用Identity和Visual Studio的默认模板。这里一个关于Identity的Stackoverflow问答,你可能也会感兴趣。

非常感谢。这帮了我很多。实际上,我对洋葱架构和简单注入器都是完全陌生的。客户端有一些限制,我必须使用基于数据库的洋葱架构,并使用ASP.NET身份框架。我在互联网上没有找到足够的帮助来满足我的需求。但无论如何,非常感谢。我会阅读所有这些文章并尝试实现它们。 - Usman Khalid
我不知道你在这里想要表达什么意思:“你不应该自动装配框架类型,比如UserManager<TUser, TKey>,而是应该通过手动注册来创建这样的类型。” 你是想说我不应该自定义Identity UserManager吗? - Usman Khalid
@UsmanKhalid:不,自动装配是容器选择正确的构造函数并自动注入正确的依赖项的过程。手动装配是您的代码调用该构造函数的过程。这就是我的示例所做的。它们在 lambda 表达式中调用 ctor。 - Steven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接