Get user with assigned roles

2020-02-14 03:24发布

问题:

Using ASP.NET Core identity, I create a new user with UserManager.CreateAsync() and assign them to an existing role with UserManager.AddToRoleAsync. This works, as the realtion between user and role is stored in the AspNetUserRoles table of the database.

But when I fetch the user using the UserManager (e.g. UserManager.FindByMail() method) then the Role list is empty. I also tried the Include function from EF like this:

var user = userManager.Users.Include(u => u.Roles).FirstOrDefault(u => u.Email == "test@test.de");

This gave me the Ids of the n:m association table, which is not very usefull as I need the role names. Loading them using a second query is also not possible, since the Roles attribute of the identity user is readonly. I would expect to get a List<string> of the role-names. Couldn't find any information about this.

For me the only workaround seems to add a custom attribute to my user and fill them with the data, which I fetch using a second query. But thats not a nice solution. Cant belive that ASP.NET Core Identity has no better way of getting those data...

回答1:

UserManager does not load the relations by default.

The manual inclusion is a good way but as stated here - direct M:N relationships are not yet supported by EntityFramework Core.

So there are two ways I see:

(The preffered one) Use

    userManager.GetRolesAsync(user);

This will return a List<string> with user's role names. Or use some EF query to get an IdentityRole objects by joined IdentityUserRole. Unfortunatelly, this requires an acceptance with the fact the roles will not be directly in the User entity.

OR you can implement custom IdentityUserRole, create a relation to IdentityRole there and then query it with `

Include(user => user.Roles).ThenInclude(role => role.Role)

How to implement own Identity entities is described e.g. here. But it's complicated approach and the Role objects will be nested in the binding entities.


However, you can declare a property in your ApplicationUser:

[NotMapped]
public List<string> RoleNames {get; set;}

and use it at you free will...



回答2:

Here is the solution I came up with. It may not be the most efficient. Hope it helps someone.

public class UserVM
{
    public string Id { get; set; }
    public string UserName { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Roles { get; set; }
}

// Project each element of query into List<UserVM>
var list = (from user in _userManager.Users
            select new UserVM
            {
                Id = user.Id,
                UserName = user.UserName,
                Name = user.Name,
                Email = user.Email
            }).ToList();

list.Select(async user =>
{
    var userEntity = await _userManager.FindByIdAsync(user.Id);
    user.Roles = string.Join("; ", await _userManager.GetRolesAsync(userEntity));
}).ToList();