使用多个身份用户时没有类型 Identity.UserManager 的服务
No service for type Identity.UserManager when using multiple identity users
我的设置
目前,我有两个继承自 ApplicationUser
的模型,后者继承了 IdentityUser
。用户 类 是:
public abstract class ApplicationUser : IdentityUser
{
[PersonalData]
public string FirstName { get; set; }
[PersonalData]
public string LastName { get; set; }
[NotMapped]
public string FullName => $"{FirstName} {LastName}";
}
public class StudentUser : ApplicationUser
{
[PersonalData]
[Required]
public string StudentNumber { get; set; }
// A user belongs to one group
public Group Group { get; set; }
}
public class EmployeeUser : ApplicationUser { }
ApplicationUser
包含 共享 属性,例如名字和姓氏。 StudentUser
和 EmployeeUser
都有自己的 属性和关系。此结构遵循 Table Per Hierarchy (TPH) 继承。
理想情况下,我想遵循Table Per Type (TPT)继承,因为SQL结构更好。 ASP.NET Core 仅原生支持 TPH,所以这就是我遵循 TPT 方法的原因。
问题
我在 Startup.cs
中添加了身份服务:
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
当我调用 UserManager<StudentUser>
或 UserManager<EmployeeUser>
时,出现以下错误:
No service for type 'Microsoft.AspNetCore.Identity.UserManager`1[ClassroomMonitor.Models.StudentUser]' has been registered.
我的问题
不幸的是,我找不到太多关于此错误与此实现相结合的信息。
是否(甚至)可以让它以这种方式工作?
欢迎任何帮助或想法。
更新 1
手动添加 StudentUser
或 EmployeeUser
作为作用域服务似乎不起作用(提到第一个 )。
services.AddScoped<UserManager<ApplicationUser>, UserManager<ApplicationUser>>();
// or..
services.AddScoped<UserManager<ApplicationUser>>();
这会引发以下错误:
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.IUserStore1[ClassroomMonitor.Models.StudentUser]'
更新 2
这里有一个 Gist 可以让您更好地了解项目结构:
您缺少它的寄存器 DI。
services.AddScoped<UserManager<AppUser>, UserManager<AppUser>>()
StudentUser和EmployeeUser类似
在新项目上测试:
dotnet new mvc --auth Individual
Startup.cshtml
services.AddDefaultIdentity<User>()
.AddEntityFrameworkStores<ApplicationDbContext>();
User.cs
public class User : IdentityUser
{
public string Test { get; set; }
}
可能这是你的问题:
_LoginPartial.cshtml
@inject SignInManager<User> SignInManager
@inject UserManager<User> UserManager
也这样测试过:
Startup.cs
services.AddDefaultIdentity<User2>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Users.cs
public class User : IdentityUser
{
public string TestA { get; set; }
}
public class User2 : User
{
public string TestB { get; set; }
}
_LoginPartial.cshtml
@inject SignInManager<User2> SignInManager
@inject UserManager<User2> UserManager
理想情况下,您将为派生用户类型调用与基本用户类型相同的身份设置。
不幸的是,AddIdentity
方法包含一些阻止多次使用它的代码。
相反,您可以使用 AddIdentityCore
. The role services are already registered by the AddIdentity
, the only difference is that AddIdentityCore
registers UserClaimsPrincipalFactory<TUser>
, so in order to match AddIdentity
setup it needs to be replaced with UserClaimsPrincipalFactory<TUser, TRole>
via AddClaimsPrincipalFactory
方法。
代码看起来像这样:
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
services.AddIdentityCore<StudentUser>()
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<StudentUser, IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
services.AddIdentityCore<EmployeeUser>()
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<EmployeeUser, IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
当然你可以在自定义扩展方法中移动公共部分。
更新:虽然角色服务已经配置好,但您仍然需要调用AddRoles
才能正确设置Role
属性 的 IndentityBuilder
,然后由 AddEntityFrameworkStores
.
使用
你不能为不同的用户类型添加作用域,你真的不应该有许多从 IdentityUser 派生的不同类型,因为这意味着你要么在整个地方使用不正确的类型,要么在数据库。
你真的应该构建你的数据,所以它有一个 ApplicationUser
被员工实体(一个单独的实体)或学生实体(再次是一个单独的实体)引用。
这里更多的是设计问题而不是代码问题。
ASPIdentity 将在您 AddIdentity<ApplicationUser, IdentityRole>
时注入 Usermanager<ApplicationUser>
,因此添加更多用户管理器将无法按预期工作。
答案
您必须为每种类型的用户创建不同的实体,1 个用于学生,1 个用于员工等。这些都将有一个指向用户 ID 的外键,这将使您能够添加多种类型的用户而无需不同的表每个用户类型。
然后当你 addIdentity
你可以注册 ApplicationUser
(就像现在一样)然后注入 UserManager<ApplicationUser>
这将获得用户类型。
如果核心>=3.0
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<WorldContext>();
我的设置
目前,我有两个继承自 ApplicationUser
的模型,后者继承了 IdentityUser
。用户 类 是:
public abstract class ApplicationUser : IdentityUser
{
[PersonalData]
public string FirstName { get; set; }
[PersonalData]
public string LastName { get; set; }
[NotMapped]
public string FullName => $"{FirstName} {LastName}";
}
public class StudentUser : ApplicationUser
{
[PersonalData]
[Required]
public string StudentNumber { get; set; }
// A user belongs to one group
public Group Group { get; set; }
}
public class EmployeeUser : ApplicationUser { }
ApplicationUser
包含 共享 属性,例如名字和姓氏。 StudentUser
和 EmployeeUser
都有自己的 属性和关系。此结构遵循 Table Per Hierarchy (TPH) 继承。
理想情况下,我想遵循Table Per Type (TPT)继承,因为SQL结构更好。 ASP.NET Core 仅原生支持 TPH,所以这就是我遵循 TPT 方法的原因。
问题
我在 Startup.cs
中添加了身份服务:
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
当我调用 UserManager<StudentUser>
或 UserManager<EmployeeUser>
时,出现以下错误:
No service for type 'Microsoft.AspNetCore.Identity.UserManager`1[ClassroomMonitor.Models.StudentUser]' has been registered.
我的问题
不幸的是,我找不到太多关于此错误与此实现相结合的信息。
是否(甚至)可以让它以这种方式工作?
欢迎任何帮助或想法。
更新 1
手动添加 StudentUser
或 EmployeeUser
作为作用域服务似乎不起作用(提到第一个
services.AddScoped<UserManager<ApplicationUser>, UserManager<ApplicationUser>>();
// or..
services.AddScoped<UserManager<ApplicationUser>>();
这会引发以下错误:
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.IUserStore1[ClassroomMonitor.Models.StudentUser]'
更新 2
这里有一个 Gist 可以让您更好地了解项目结构:
您缺少它的寄存器 DI。
services.AddScoped<UserManager<AppUser>, UserManager<AppUser>>()
StudentUser和EmployeeUser类似
在新项目上测试:
dotnet new mvc --auth Individual
Startup.cshtml
services.AddDefaultIdentity<User>()
.AddEntityFrameworkStores<ApplicationDbContext>();
User.cs
public class User : IdentityUser
{
public string Test { get; set; }
}
可能这是你的问题:
_LoginPartial.cshtml
@inject SignInManager<User> SignInManager
@inject UserManager<User> UserManager
也这样测试过:
Startup.cs
services.AddDefaultIdentity<User2>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Users.cs
public class User : IdentityUser
{
public string TestA { get; set; }
}
public class User2 : User
{
public string TestB { get; set; }
}
_LoginPartial.cshtml
@inject SignInManager<User2> SignInManager
@inject UserManager<User2> UserManager
理想情况下,您将为派生用户类型调用与基本用户类型相同的身份设置。
不幸的是,AddIdentity
方法包含一些阻止多次使用它的代码。
相反,您可以使用 AddIdentityCore
. The role services are already registered by the AddIdentity
, the only difference is that AddIdentityCore
registers UserClaimsPrincipalFactory<TUser>
, so in order to match AddIdentity
setup it needs to be replaced with UserClaimsPrincipalFactory<TUser, TRole>
via AddClaimsPrincipalFactory
方法。
代码看起来像这样:
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
services.AddIdentityCore<StudentUser>()
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<StudentUser, IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
services.AddIdentityCore<EmployeeUser>()
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<EmployeeUser, IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
当然你可以在自定义扩展方法中移动公共部分。
更新:虽然角色服务已经配置好,但您仍然需要调用AddRoles
才能正确设置Role
属性 的 IndentityBuilder
,然后由 AddEntityFrameworkStores
.
你不能为不同的用户类型添加作用域,你真的不应该有许多从 IdentityUser 派生的不同类型,因为这意味着你要么在整个地方使用不正确的类型,要么在数据库。
你真的应该构建你的数据,所以它有一个 ApplicationUser
被员工实体(一个单独的实体)或学生实体(再次是一个单独的实体)引用。
这里更多的是设计问题而不是代码问题。
ASPIdentity 将在您 AddIdentity<ApplicationUser, IdentityRole>
时注入 Usermanager<ApplicationUser>
,因此添加更多用户管理器将无法按预期工作。
答案 您必须为每种类型的用户创建不同的实体,1 个用于学生,1 个用于员工等。这些都将有一个指向用户 ID 的外键,这将使您能够添加多种类型的用户而无需不同的表每个用户类型。
然后当你 addIdentity
你可以注册 ApplicationUser
(就像现在一样)然后注入 UserManager<ApplicationUser>
这将获得用户类型。
如果核心>=3.0
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<WorldContext>();