简体   繁体   中英

How to display a list of users with Roles - ASP.NET (Core)

I'm trying to include the Role for each User in a list as can be seen in the picture below. In the Index method I want to join the user to the role and send it to the view. But for some reason user.Roles isn't being recognized. So it seems like the navigational property is lacking. I've added a screenshot below to illustrate my problem more clearly. I've been following a couple of guides and they all seem to use user.Roles without any issues.

The code seems correct to me, is there something i'm missing here?

在此处输入图像描述

AccountController

private AppIdentityDbContext context;

public AccountController(AppIdentityDbContext _context)
{
    context = _context;
}

public IActionResult Index()
{
    var usersWithRoles = (from user in context.Users
        select new
        {
            Username = user.UserName,
            Email = user.Email,
            RoleNames = (from userRole in user.Roles
                join role in context.Roles on userRole.RoleId
                    equals role.Id
                select role.Name).ToList()
        }).ToList().Select(p => new UsersViewModel()

    {
        Username = p.Username,
        Email = p.Email,
        Role = string.Join(",", p.RoleNames)
    });

    return View(usersWithRoles);
}

UsersViewModel

public class UsersViewModel
{
    public string Username { get; set; }
    public string Email { get; set; }
    public string Role { get; set; }
}

ApplicationUser

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

AppIdentityDbContext

public class AppIdentityDbContext : IdentityDbContext<ApplicationUser>
{
    public AppIdentityDbContext(DbContextOptions<AppIdentityDbContext> options)
        : base(options) { }
}

AppDbContext

public class AppDbContext : DbContext
{

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(
            "Server=(localdb)\\MSSQLLocalDB;Database=Local;MultipleActiveResultSets=true");
    }

I get the error:

在此处输入图像描述

According to your code, it seems that you are using Asp.net Core Identity with custom custom user data and Roles.

First, please check the Startup.ConfigureServices method, make sure you have add Roles to the ApplicationUser. Like this:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));

        services.AddIdentity<ApplicationUser, IdentityRole>(options => options.SignIn.RequireConfirmedAccount = true)
                 .AddDefaultUI()
                 .AddEntityFrameworkStores<ApplicationDbContext>()
                 .AddDefaultTokenProviders();

        //or using the following code.
        //services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
        //    .AddRoles<IdentityRole>()
        //    .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddControllersWithViews();
        services.AddRazorPages();

    }

You can refer this article to learn how to add Roles with asp.net Core identity.

Then, in the controller, you could use the UserManager.GetRolesAsync method to get a list of role names the specified user belongs to. Code like this:

public class ApplicationUserController : Controller
{
    private readonly UserManager<ApplicationUser> _userManager;

    private readonly ApplicationDbContext _context;
    public ApplicationUserController(UserManager<ApplicationUser> usermanager, ApplicationDbContext context)
    {
        _userManager = usermanager;
        _context = context;
    }
    public IActionResult Index()
    {
        var users = _userManager.Users.Select(c => new UsersViewModel()
        {
            Username = c.UserName,
            Email = c.Email,
            Role = string.Join(",", _userManager.GetRolesAsync(c).Result.ToArray())
        }).ToList();

        return View(users);
    }
}

The result like this:

在此处输入图像描述

Besides, when using the Asp.net Identity, the database will use a AspNetUserRoles table to store the relationship between AspNetUsers table and AspNetRoles table (you could use SQL Server Management Studio to check the database tables). If you don't want to use UserManager to get the user's roles, you could join the AspNetUsers, AspNetUserRoles and AspNetRoles table and query the database and get the required properties. Code as below:

public class ApplicationUserController : Controller
{
    private readonly UserManager<ApplicationUser> _userManager;

    private readonly ApplicationDbContext _context;
    public ApplicationUserController(UserManager<ApplicationUser> usermanager, ApplicationDbContext context)
    {
        _userManager = usermanager;
        _context = context;
    }
    public IActionResult Index()
    { 
        var result = _context.Users
            .Join(_context.UserRoles, u => u.Id, ur => ur.UserId, (u, ur) => new { u, ur })
            .Join(_context.Roles, ur => ur.ur.RoleId, r => r.Id, (ur, r) => new { ur, r }) 
            .Select(c => new UsersViewModel()
            {
                Username = c.ur.u.UserName,
                Email = c.ur.u.Email,
                Role = c.r.Name
            }).ToList().GroupBy(uv=> new { uv.Username, uv.Email }).Select(r=> new UsersViewModel()
            {
                Username = r.Key.Username,
                Email = r.Key.Email,
                Role = string.Join(",", r.Select(c=>c.Role).ToArray())
            }).ToList();

        // you could also use the following code:
        var result2 = _context.Users
        .Join(_context.UserRoles, u => u.Id, ur => ur.UserId, (u, ur) => new { u, ur })
        .Join(_context.Roles, ur => ur.ur.RoleId, r => r.Id, (ur, r) => new { ur, r })
        .ToList()
        .GroupBy(uv => new { uv.ur.u.UserName, uv.ur.u.Email }).Select(r => new UsersViewModel()
        {
            Username = r.Key.UserName,
            Email = r.Key.Email,
            Role = string.Join(",", r.Select(c => c.r.Name).ToArray())
        }).ToList();

        return View(result);
    }
}

By using the above linq command, we could also get the same result.

在此处输入图像描述

Additional resource:

The Db context:

public class ApplicationDbContext : IdentityDbContext
{
    public DbSet<ApplicationUser> ApplicationUsers { get; set; }
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    }
}

public class ApplicationUser: IdentityUser
{
    public int Age { get; set; }
    public string CustomTag { get; set; }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM