No service for type Identity.UserManager when using multiple identity users

孤街浪徒 提交于 2019-11-30 17:30:47

Ideally you would call the same identity setup for the derived user types as for the base user type.

Unfortunately AddIdentity method contains some code that prevents of using it more than once.

Instead, you could use 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 method.

The code looks like something like this:

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

Of course you could move the common parts in a custom extension methods.

Update: Although the role services are already configured, you still need to call AddRoles in order to set correctly the Role property of the IndentityBuilder, which then is used by the AddEntityFrameworkStores.

You are missing register DI for it.

services.AddScoped<UserManager<AppUser>, UserManager<AppUser>>()

StudentUser and EmployeeUser are similar to it

Tested on fresh project:

dotnet new mvc --auth Individual

Startup.cshtml

services.AddDefaultIdentity<User>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

User.cs

public class User : IdentityUser
{
    public string Test { get; set; }
}

Probably here's your problem:

_LoginPartial.cshtml

@inject SignInManager<User> SignInManager
@inject UserManager<User> UserManager

Also tested this way:

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

You cannot add scoped for the different user types, you should really not have many different types which are derived from IdentityUser as it will mean you will either have incorrect types used all over the place or multiple different user tables in the database.

you should really structure your data so it has an ApplicationUser which is referenced by the employee entity (a separate entity) or the Student entity (again a separate entity). there is more of a design issue here rather than a code issue.

ASPIdentity will inject the Usermanager<ApplicationUser> when you AddIdentity<ApplicationUser, IdentityRole>, so adding more user managers will not work as expected.

The answer you must create different entities for every type of user, 1 for student, 1 for employee, etc. these will all have a Foreign Key to the user's id, and that will enable you to add multiple types of user without the need for different tables per user type.

then when you addIdentity you can register ApplicationUser (as is at the moment) then inject UserManager<ApplicationUser> which will get the user type.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!