尝试激活“AuthController”时,无法解析类型为“Microsoft.AspNetCore.Identity.UserManager”的服务。

165

我在登录控制器中遇到了这个错误。

InvalidOperationException:尝试激活“Automobile.Server.Controllers.AuthController”时,无法解析类型为“Microsoft.AspNetCore.Identity.UserManager`1[Automobile.Models.Account]”的服务。

这是Auth Controller的构造函数:

private SignInManager<Automobile.Models.Account> _signManager;
    private UserManager<Automobile.Models.Account> _userManager;

    public AuthController(UserManager<Models.Account> userManager,
                          SignInManager<Automobile.Models.Account> signManager)
    {
        this._userManager = userManager;
        this._signManager = signManager;
    }

这里是 startup.cs 中的 ConfigureServices:

public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddApplicationInsightsTelemetry(Configuration);
        services.Configure<AppConfig>(Configuration.GetSection("AppSettings"));

        //var provider = HttpContext.ApplicationServices;
        //var someService = provider.GetService(typeof(ISomeService));


        services.AddDbContext<Providers.Database.EFProvider.DataContext>(options => options
            .UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                 b => b.MigrationsAssembly("Automobile.Server")
            ));


        services.AddIdentity<IdentityUser, IdentityRole>(options =>
        {
            options.User.RequireUniqueEmail = false;
        })
        .AddEntityFrameworkStores<Providers.Database.EFProvider.DataContext>()
        .AddDefaultTokenProviders(); 
        //services.AddScoped<SignInManager<Automobile.Models.Account>, SignInManager<Automobile.Models.Account>>();
        //services.AddScoped<UserManager<Automobile.Models.Account>, UserManager<Automobile.Models.Account>>();

        services.AddMvc();
        App.Service = services.BuildServiceProvider();

        // Adds a default in-memory implementation of IDistributedCache.
        services.AddDistributedMemoryCache();

        services.AddSession(options =>
        {
            // Set a short timeout for easy testing.
            options.IdleTimeout = TimeSpan.FromSeconds(10);
            options.CookieHttpOnly = true;
        });

    }

30
我觉得你正在将 IdentityUser 注册为基本用户类,但随后你使用的是 Automobile.Models.Account,这在 ASP.NET Identity 中并没有注册。请注意不要更改原意,我会让翻译更通俗易懂。 - Federico Dipuma
@FedericoDipuma 非常感谢 :) 已解决。 - OMID
你是如何解决它的? - Rafael
5
在services.AddIdentity中,只需将IdentityUser替换为您的Identity用户类即可。 - OMID
2
@OMID 为什么不把你的评论发表为答案,这个解决了我的问题,但在经历了一些严重的研究和开发头痛之后.. - Naila Akbar
10个回答

154

在SignInManager、UserManager和services.AddIdentity中需要使用相同的用户数据模型。如果您正在使用自己定义的应用角色模型类,同样的原则也适用。

因此,请更改

services.AddIdentity<IdentityUser, IdentityRole>(options =>
    {
        options.User.RequireUniqueEmail = false;
    })
    .AddEntityFrameworkStores<Providers.Database.EFProvider.DataContext>()
    .AddDefaultTokenProviders();

services.AddIdentity<Automobile.Models.Account, IdentityRole>(options =>
    {
        options.User.RequireUniqueEmail = false;
    })
    .AddEntityFrameworkStores<Providers.Database.EFProvider.DataContext>()
    .AddDefaultTokenProviders();

2
我有类似的问题,我在AddIdentity方法中定义了我的客户用户和角色,但仍然遇到相同的错误。有什么想法吗?我可以在一个单独的线程中发布我的代码。 - devC
1
实际上,我已经解决了那个问题,但是现在遇到了创建数据库连接的问题。我将发布这个问题。 - devC
https://stackoverflow.com/questions/48161467/database-connection-not-created-in-identitydbcontext - devC
似乎您的连接字符串设置不正确,请查看我在您的帖子中的答案。 - HojjatK

80

为了明确答案:

如果您在startup.cs中使用类ApplicationUser: services.AddIdentity<ApplicationUser,IdentityRole>()

那么在注入控制器时,必须使用相同的类:

public AccountController(UserManager<ApplicationUser> userManager)

如果您使用其他类,如:

public AccountController(UserManager<IdentityUser> userManager)

那么您将会得到这个错误:

InvalidOperationException: 无法解析类型为 'Microsoft.AspNetCore.Identity.UserManager`1[IdentityUser]' 的服务

因为您在启动时使用了 ApplicationUser 而不是 IdentityUser,所以该类型未在注入系统中注册。


6
这适用于所有引用,因此如果您实施了新的Razor身份验证来替换旧的身份验证系统,则需要将其自动实现的东西(例如SignInManager <IdentityUser>)替换为SignInManager<ApplicationUser>。这可能很烦人。另外,您需要从普通的/Account/Login重新路由到/Identity/Account/Login等。这是一些提示,可以帮助您。 ;) - Johan Herstad
这不应该是被接受的答案,但它应该在这里并被突出显示。在我意识到愚蠢的默认类用于用户身份之前,我花了两个小时来尝试解决它。好吧,"意识到"指的是"阅读你的答案"。 :) - Konrad Viltersten

41

这与原帖有些无关,但既然您通过谷歌来到这里……如果您正在使用以下内容并且遇到此错误:

services.AddIdentityCore<YourAppUser>()

然后,您将需要手动注册 AddIdentity 执行的内容,可以在此处找到: https://github.com/aspnet/Identity/blob/feedcb5c53444f716ef5121d3add56e11c7b71e5/src/Identity/IdentityServiceCollectionExtensions.cs#L79

        services.AddHttpContextAccessor();
        // Identity services
        services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
        services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
        services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
        services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
        services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>();
        // No interface for the error describer so we can add errors without rev'ing the interface
        services.TryAddScoped<IdentityErrorDescriber>();
        services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
        services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<TUser>>();
        services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
        services.TryAddScoped<UserManager<TUser>>();
        services.TryAddScoped<SignInManager<TUser>>();
        services.TryAddScoped<RoleManager<TRole>>();
你需要用你自己的TUserTRole实现替换,或者使用默认的IdentityUserIdentityRole

需要创建一个自定义的SignInManager,这样就可以解决问题了。如果您打算这样做,请查看https://github.com/dotnet/docs/issues/14828。 - perustaja
1
我最初走了这条路,但发现这里的解决方案(https://dev59.com/obnoa4cB1Zd3GeqPYt3u#60752194)更加直接;在重新排序`AddIdentity`和`AddJwtBearer`之后,我唯一需要做的更改是设置示例中显示的所有三个选项;我之前只使用了`DefaultAuthenticationScheme`。我仍然可以在登录时获取cookie,但是`[Authorize]`现在可以在不指定AuthenticationSchema的情况下为JWT令牌工作。 - Aaron
3
这正是我所缺少的。将 TryAddScoped<UserManager<TUser>>();services.TryAddScoped<SignInManager<TUser>>(); 添加到我的 Startup.cs 中解决了我的问题。 - MorganR
1
请注意,其中一些已经注册 - IdentityCore 跳过了例如 SignInManager / RoleManager - Mr Patience
我认为我下面添加的解决方案在这种情况下更简单,并且对我起作用。 - JMIII
我正在使用 .net 6,并且还需要添加 IUserStoreIRoleStoreISystemClock。完整代码请参见下面的答案。 - BurnsBA

11
在Startup类的ConfigureServices方法中,您可以分别设置IdentityUser和IdentityRole,如下所示:
services.AddDefaultIdentity<IdentityUser>()
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

或者

您可以直接在AddIdentity中进行配置:

services.AddIdentity<IdentityUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>();

7
仅提供代码答案,问题的提问者和其他人很难了解问题的解决方法。建议编辑答案并添加解释。 - Cleptus

6
不要忘记在 ConfigureServices 中添加角色管理器。
services.AddDefaultIdentity<IdentityUser>()
    .AddRoles<IdentityRole>() // <--------
    .AddDefaultUI(UIFramework.Bootstrap4)
    .AddEntityFrameworkStores<ApplicationDbContext>();

1

对我来说,在Dot.Net Core 7中添加服务的顺序非常重要。

在program.cs中的这段代码导致了错误:

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddRoles<IdentityRole>();

这里的语句被翻转了。这段代码运行正常:

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

0

这与原帖有些不相关,但既然谷歌把你带到了这里...而且这是一个更简单的解决方案,如果你遇到了这个错误并且正在使用:

services.AddIdentityCore()

有一个比上面列出的答案更简单的解决方案。

假设您有一个名为ApplicationUser的自定义IdentityUser和一个名为ApplicationRole的自定义角色,您可以简单地使用以下内容来工作。

builder
    .Services
    .AddIdentityCore<ApplicationUser>(identityOptions =>
                                      {
                                          identityOptions.Lockout = new LockoutOptions
                                          {
                                              DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30)
                                              , MaxFailedAccessAttempts = 20
                                          };

                                          identityOptions.Password = new PasswordOptions
                                          {
                                              RequireDigit = true
                                              , RequireLowercase = true
                                              , RequireNonAlphanumeric = true
                                              , RequireUppercase = true
                                              , RequiredLength = 8
                                          };

                                          identityOptions.SignIn = new SignInOptions
                                          {
                                              RequireConfirmedAccount = true
                                              , RequireConfirmedEmail = true
                                          };

                                          identityOptions.User = new UserOptions
                                          {
                                              AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.@1234567890!#$%&'*+-/=?^_`{|}~"
                                              , RequireUniqueEmail = true
                                          };
                                      })
    .AddRoles<ApplicationRole>()
    .AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<ApplicationUser, ApplicationRole>>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

这个简单多了。

同时,从微软的文档来看,你必须像下面这样声明你的DbContext才能推断出它。

public class ApplicationDbContext
    : IdentityDbContext<ApplicationUser
        , ApplicationRole
        , long
        , ApplicationUserClaim
        , ApplicationUserRole
        , ApplicationUserLogin
        , ApplicationRoleClaim
        , ApplicationUserToken>
{
}

当然,您不必使用我在此处使用的自定义类型,可以使用默认值等。


哦,这是一个适用于每个人的好答案,可以使用services.AddIdentityCore() - undefined

0
如果您正在使用“IdentityServer”,则IdentityServer会对用户进行身份验证并授权客户端。默认情况下,IdentityServer实际上不涉及用户管理。但是,它确实支持asp.net Identity
因此,您需要添加:
services.AddIdentityServer()
    .AddAspNetIdentity<ApplicationUser>();

0
您需要更新您的Startup.cs类如下:

services.AddIdentity<ApplicationUser,IdentityRole>() .AddEntityFrameworkStores();

这里:ApplicationUser 是我的自定义模型类。


-1

类似于上面的答案,但我必须添加 IUserStoreIRoleStore。此外,安全戳验证器抱怨未注册 ISystemClock(可从 Microsoft.AspNetCore.Authentication 获得),因此也在这里。

下面的类型是根据标准 Identity 数据库表(dbo.AspNetUsers、dbo.AspNetRoles 等)命名的。下面的 Guid 类型是这些表的主键类型。默认情况下,这是 string,因此请根据您的模型进行调整。

/* begin services to support app custom identity */

// Add the system clock service
services.AddSingleton<ISystemClock, SystemClock>();

services.TryAddScoped<
    IUserStore<AspNetUser>,
    UserStore<AspNetUser, AspNetRole, ApplicationDbContext, Guid, AspNetUserClaim, AspNetUserRole, AspNetUserLogin, AspNetUserToken, AspNetRoleClaim>>();

services.TryAddScoped<
    IRoleStore<AspNetRole>,
    RoleStore<AspNetRole, ApplicationDbContext, Guid, AspNetUserRole, AspNetRoleClaim>>();

// Identity services
services.TryAddScoped<IUserValidator<AspNetUser>, UserValidator<AspNetUser>>();
services.TryAddScoped<IPasswordValidator<AspNetUser>, PasswordValidator<AspNetUser>>();
services.TryAddScoped<IPasswordHasher<AspNetUser>, PasswordHasher<AspNetUser>>();
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.TryAddScoped<IRoleValidator<AspNetRole>, RoleValidator<AspNetRole>>();
// No interface for the error describer so we can add errors without rev'ing the interface
services.TryAddScoped<IdentityErrorDescriber>();
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<AspNetUser>>();
services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<AspNetUser>>();
services.TryAddScoped<IUserClaimsPrincipalFactory<AspNetUser>, UserClaimsPrincipalFactory<AspNetUser, AspNetRole>>();
services.TryAddScoped<IUserConfirmation<AspNetUser>, DefaultUserConfirmation<AspNetUser>>();
services.TryAddScoped<UserManager<AspNetUser>>();
services.TryAddScoped<SignInManager<AspNetUser>>();
services.TryAddScoped<RoleManager<AspNetRole>>();

/* end services to support app custom identity */

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