web-dev-qa-db-fra.com

Aucun service pour le type 'Microsoft.AspNetCore.Identity.UserManager` StudentUser

Ma configuration

Actuellement, j'ai deux modèles qui héritent de ApplicationUser, qui est un type IdentityUser. Les classes d'utilisateurs sont:

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

La ApplicationUser contient les propriétés partagées, comme le prénom et le nom. StudentUser et EmployeeUser ont tous les deux leurs propriétés et leurs relations own. Cette structure suit l'héritage Table par hiérarchie (TPH)

Idéalement, je veux suivre l'héritage Table par type (TPT) , car la structure SQL serait meilleure. .NET Core ne supporte que TPH de manière native, c'est pourquoi je suis cette approche.

Le problème

Dans Startup.cs j'ai ajouté le service d'identité:

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

Lorsque j'appelle UserManager<StudentUser> ou UserManager<EmployeeUser>, j'obtiens le message d'erreur suivant:

Aucun service pour le type 'Microsoft.AspNetCore.Identity.UserManager`1 [ClassroomMonitor.Models.StudentUser]' n'a été enregistré.

Ma question

Malheureusement, je ne trouve pas grand chose à propos de cette erreur dans cette implémentation. Est-il possible (même) de le faire fonctionner de cette façon?

Toute aide ou pensées sont les bienvenues. 

Mise à jour 1

L'ajout manuel de StudentUser ou EmployeeUser en tant que services étendus ne semble pas fonctionner (mentionné en tant que premier answer ).

services.AddScoped<UserManager<ApplicationUser>, UserManager<ApplicationUser>>();
// or..
services.AddScoped<UserManager<ApplicationUser>>();

Cela lève l'erreur suivante:

InvalidOperationException: impossible de résoudre le service pour le type 'Microsoft.AspNetCore.Identity.IUserStore1 [ClassroomMonitor.Models.StudentUser]' 

Mise à jour 2

Voici un Gist pour vous donner une meilleure image de la structure du projet: 

12
Matthijs

Idéalement, vous appelez la même configuration d'identité pour les types d'utilisateurs dérivés que pour le type d'utilisateurs de base.

Malheureusement, AddIdentity method contient du code qui l’empêche de l’utiliser plusieurs fois.

Au lieu de cela, vous pouvez utiliser AddIdentityCore . Les services de rôle sont déjà enregistrés par la variable AddIdentity. La seule différence est que AddIdentityCore enregistre UserClaimsPrincipalFactory<TUser> et que, pour correspondre à la configuration AddIdentity, il doit être remplacé par UserClaimsPrincipalFactory<TUser, TRole> via AddClaimsPrincipalFactory méthode.

Le code ressemble à quelque chose comme ça:

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

Bien sûr, vous pouvez déplacer les parties communes dans une méthode d'extension personnalisée.

Update: Bien que les services de rôle soient déjà configurés, vous devez toujours appeler AddRoles afin de définir correctement la propriété Role de IndentityBuilder, qui est ensuite utilisée par AddEntityFrameworkStores.

2
Ivan Stoev

Il vous manque le registre DI pour cela. 

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

StudentUser et EmployeeUser lui ressemblent

0

Testé sur un nouveau projet:

dotnet new mvc --auth Individual

Startup.cshtml

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

Utilisateur.cs

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

Probablement voici votre problème:

_LoginPartial.cshtml

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

Également testé de cette façon:

Startup.cs

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

Utilisateurs.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
0
UbuntuCore

Vous ne pouvez pas ajouter d’étendue pour les différents types d’utilisateur, vous ne devriez pas avoir beaucoup de types différents dérivés d’IdentityUser, cela voudrait dire que vous aurez soit des types incorrects utilisés partout ou plusieurs tables d’utilisateur différentes dans la base de données.

vous devriez vraiment structurer vos données de manière à ce qu'elles aient une variable ApplicationUser qui soit référencée par l'entité employé (une entité distincte) ou l'entité Étudiant (encore une fois une entité distincte) . .

ASPIdentity injectera le Usermanager<ApplicationUser> lorsque vous AddIdentity<ApplicationUser, IdentityRole>, de sorte que l'ajout de plusieurs gestionnaires d'utilisateurs ne fonctionnera pas comme prévu.

La réponse vous devez créer différentes entités pour chaque type d'utilisateur, 1 pour l'étudiant, 1 pour l'employé, etc. Elles auront toutes une clé étrangère associée à l'ID de l'utilisateur, ce qui vous permettra d'ajouter plusieurs types d'utilisateur sans avoir besoin de tables différentes. par type d'utilisateur.

alors quand vous addIdentity vous pourrez enregistrer ApplicationUser (comme c'est le moment) puis injectez UserManager<ApplicationUser> qui obtiendra le type d'utilisateur.

0
Kyle B Cox