List of Users with roles in MVC Asp.net identity
Asked Answered
S

5

13

I want to have list of all the users registered on my site with their roles.

Id | Name | Role


1 | ABC | Admin


2 | DEF | User

Something like this, I have made Roles controller in which all the roles is listed.

 public ActionResult Index()
    {
        var roles = context.Roles.ToList();
        return View(roles);
    }

In View

@model IEnumerable<Microsoft.AspNet.Identity.EntityFramework.IdentityRole>
@{
    ViewBag.Title = "Index";
}    
<div>
    @foreach (var role in Model)
    {
        <p>
            <strong>@role.Name | </strong>
        </p>
    }
</div>

This will list all the roles but i want user's list with their roles.

Please give any solution, Thanks

Schramm answered 3/1, 2015 at 20:1 Comment(3)
context.Users should have Roles property for each user: var usersWithRoles = context.Users.Select(x => new UserWithRolesViewModel {User = x, UserRoles = x.Roles}).ToList();Carolynncarolynne
Which namespace should i add in the View of this actionResult Method?Schramm
and what is 'UserWithRolesViewModel' after new keyword ? I am sorry for asking such silly things but i am new in MVC developmentSchramm
S
12

Create a new class called UserViewModel. This will act as a view model for your page.

public class GroupedUserViewModel
{
    public List<UserViewModel> Users {get; set;}
    public List<UserViewModel> Admins {get; set;}
}

public class UserViewModel
{
    public string Username {get; set;}
    public string Roles {get; set;}
}

In the controller's action method, get the list of users along with their roles and map that to the UserViewModel.

public ActionResult Index()
{
    var allusers = context.Users.ToList();
    var users = allusers.Where(x=>x.Roles.Select(role => role.Name).Contains("User")).ToList();
    var userVM = users.Select(user=>new UserViewModel{Username = user.FullName, Roles = string.Join(",", user.Roles.Select(role=>role.Name))}).ToList();

    var admins = allusers.Where(x=>x.Roles.Select(role => role.Name).Contains("Admin")).ToList();
    var adminsVM = admins.Select(user=>new UserViewModel{Username = user.FullName, Roles = string.Join(",", user.Roles.Select(role=>role.Name))}).ToList(); 
    var model = new GroupedUserViewModel{Users = userVM, Admins = adminsVM};

    return View(model);
}

Then use the new model in the view. Make sure to use correct namespace here where you defined your view model.

@model Models.GroupedUserViewModel
@{
    ViewBag.Title = "Index";
}    
<div>
    @foreach (var user in Model.Admins)
    {
        <p>
            <strong>@user.Username | @user.Roles </strong>
        </p>
    }

    @foreach (var user in Model.Users)
    {
        <p>
            <strong>@user.Username | @user.Roles </strong>
        </p>
    }
</div>
Sulph answered 3/1, 2015 at 22:35 Comment(13)
Thank you, I have tried this. It is displaying the list of users but in roles coulmn it is not displaying the name of roles. I want the role name such as Admin, User.Schramm
'System.Data.Entity.DynamicProxies.IdentityUserRole_3D0B060DC86D63C1E4CDDA517BFE9D83ADB0E80' this is what it is showing in Role columnSchramm
Thank you so much, It works :D If u can tell me one more thing what if I want to group Users according to the Roles, like all the Admins together then all the UsersSchramm
Its not able to access Role Name in context.Users, getting error in this (x=>x.Role.Name.Equals("User")) and (x=>x.Role.Name.Equals("Admin")) 'Models.ApplicationUser' does not contain a definition for 'Role' and no extension method 'Role' accepting a first argument of type 'Models.ApplicationUser' could be found (are you missing a using directive or an assembly reference?)Schramm
Yes, it should be Roles instead of Role but that leads to the question what would you do if a user is in both "User" and "Admin" roles?Sulph
If a user is both then it will be listed in both admin and user, and after correcting it to Roles its showing error because Name can't be accessed, this is the error 'System.Collections.Generic.ICollection<Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole>' does not contain a definition for 'Name' and no extension method 'Name' accepting a first argument of type 'System.Collections.Generic.ICollection<Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole>' could be found (are you missing a using directive or an assembly reference?)Schramm
That is because Roles is a collection of objects (role) that has a property of Name. I have updated the code to reflect that.Sulph
Oh alright, I got it, Its working perfectly fine now. Jazakallah, May allah reward u for this kind and detailed help :)Schramm
could you please give some guidance on my question #27784711 (somewhat related to Display list of data on the basis of Roles), Thank you!Schramm
If you're using the latest versions of Asp.net.identity then avoid going direct to the context - use the API"s to get the data.Mokpo
I'm not sure why this is the accepted answer. It is wrong. Roles is a collection of IdentityUserRole objects, which do NOT have a Name property. The code does not work.Legist
Interesting way of doing it. I've spent waaaay too long trying to make this work and this answer did it for me...I'm not a big fan of the queries...but it works. I'm just wondering how viable this answer will be as the EF gets updated. It should prevail, right?Roughhew
this is still wrong. cannot access Name propertyRow
N
8

Although it is very late to answer this question, but here it is for the future visits:

Create view model class:

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

Then populate this view model class in controller:

var usersWithRoles = (from user in context.Users
                      from userRole in user.Roles
                      join role in context.Roles on userRole.RoleId equals 
                      role.Id
                      select new UserViewModel()
                      {
                          Username = user.UserName,
                          Email = user.Email,
                          Role = role.Name
                      }).ToList();

Here, context.Users represents the AspNetUsers table which has a navigation property Roles which represents the AspNetUserInRoles table. Then we perform join of context.Roles which represents the AspNetRoles table to get the role name.

Now return this list to your Index view:

return View(userWithRoles);

In the view show the list of users with roles:

@model IEnumerable<MyProject.Models.UserViewModel>
<div class="row">
        <h4>Users</h4>

        @foreach (var user in Model)
        {
            <p>
                <strong>
                    @user.Username | @user.Email | @user.Role
                </strong>
            </p>
        }            
</div>

Edit: To get multiple roles of user(if assigned any)

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

                     {
                         Username = p.Username,
                         Email = p.Email,
                         Role = string.Join(",", p.RoleNames)
                     });
Namaqualand answered 14/8, 2017 at 10:49 Comment(3)
Thank you Zahir, your answer is really helpful. :)Rhatany
If a user has more than one roles, multiple records. of the same user are created. Can we list all the roles assigned to the user in a single column?...Also if a user has no roles, they are not displayed, how can we show the users who are not assigned any roles?Ty
@20B2, I have updated my answer, now it also shows an option to show multiple roles in single column(comma separated). It also includes those users who are not assigned any rolesNamaqualand
S
5

I have a solution as above.
This is a solution in MVC 6.

In AccountViewModel.cs add models

public class GroupedUserViewModel
{
    public List<UserViewModel> Users { get; set; }
    public List<UserViewModel> Admins { get; set; }
}
public class UserViewModel
{
    public string Username { get; set; }
    public string Email { get; set; }
    public string RoleName { get; set; }
}

the controller is as follows:

    public ActionResult Index()
    {            
        var role = (from r in context.Roles where r.Name.Contains("Adviser") select r).FirstOrDefault();            
        var users = context.Users.Where(x => x.Roles.Select(y => y.RoleId).Contains(role.Id)).ToList();

        var userVM = users.Select(user => new UserViewModel
        {
            Username = user.UserName,
            Email = user.Email,
            RoleName = "Adviser"
       }).ToList();


        var role2 = (from r in context.Roles where r.Name.Contains("Admin") select r).FirstOrDefault();
        var admins = context.Users.Where(x => x.Roles.Select(y => y.RoleId).Contains(role2.Id)).ToList();

        var adminVM = admins.Select(user => new UserViewModel
        {
            Username = user.UserName,
            Email = user.Email,
            RoleName = "Admin"
        }).ToList();


        var model = new GroupedUserViewModel { Users = userVM, Admins = adminVM };
        return View(model); 

    }

finally the view:

@model ToroCRM.Models.GroupedUserViewModel
<div class="row">
        <h4>Users</h4>
        @foreach (var user in Model.Users)
        {
            <p>
                <strong>
                    @user.Username <br />
                    @user.Email<br />
                    @user.RoleName
                </strong>
            </p>
        }
        <h4>Advisers</h4>
        @foreach (var usera in Model.Admins)
        {
            <p>
                <strong>
                    @usera.Username <br />
                    @usera.Email<br />
                    @usera.RoleName
                </strong>
            </p>
        }
</div>
Sideling answered 28/10, 2016 at 1:39 Comment(4)
This is exactly what I was looking for. I was hoping that a better solution existed as this feels somewhat "hacky". Strange that they changes the Roles property to be a list of IdentityUserRole instead of a list of IdentityRole, as we then need to compare by Id and not just the name, though adding a user with the RoleManager still works with the role name and not Id.Frightened
This should be the answer. I have looked for this for 2 weeks.Bigley
I guess I have a knowledge gap in using LINQ. Can you point me in a direction where I can learn LINQ queries?Bigley
Personally I'd avoid the query-style Linq syntax where possible. In the above code, when looking for FirstOrDefault, you can do this with the query syntax: var role = context.Roles.FirstOrDefault(r => r.Name.Contains("Adviser"));. Sometimes the query-style syntax is better (like for joins), but generally I find the method style easier to read. I'd definitely recommend against mixing and matching like in the above example.Ketchup
A
0

I also have a solution as above. This is a solution in MVC 6. the reason for this is i try the above code and faced problems. so..

lets start off Create a new class called UserViewModel. This will act as a view model for your page

public class UserViewModel
{
    public string Username { get; set; }
    public string Email { get; set; }
    public string RoleName { get; set; }
}

The controller is as follows:

public ActionResult Index()
    { 
       List<UserViewModel> modelLst = new List<UserViewModel>();
            var role = _db.Roles.Include(x => x.Users).ToList();

            foreach (var r in role)
            {
                foreach (var u in r.Users)
                {
                    var usr = _db.Users.Find(u.UserId);
                    var obj = new UserViewModel
                    {
                        Username = usr.FullName,
                        Email = usr.Email,
                        RoleName = r.Name
                    };
                    modelLst.Add(obj);
                }

            }
     return View(modelLst); 

    }

finally the view:

@model IEnumerable<ToroCRM.Models.UserViewModel>

<div class="row">
 @foreach (var r in Model.DistinctBy(x=>x.RoleName).ToList())
    {

        <h4>@r.RoleName</h4><hr />
        <table class="table">
        foreach (var user in Model.Where(x=>x.RoleName == r.RoleName))
         {
              <tr><th>@user.Username</th><td>@user.Email</td></tr> 
         }
        </table>

    }
</div>
Azores answered 23/3, 2018 at 11:6 Comment(0)
H
0

Here's my solution to get a user with his/her role

Create a ViewModel to hold the users with the roles like below

public class UsersRoles
{
    public string UserId { get; set; }
    public string Username { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }
    public string Email { get; set; }
    public string Role { get; set; }
}

In Controller: Select all the users like below using UserManager and put them in a variable

var users = _userManager.Users.ToList();

Create a empty list: one of userRoles and give it a name List usersRoles = new List();

Loop through all the users and while looping select all the roles using the role manager and passing it the user variable. If role is not null or empty(Here you have to make sure all users have a role assigned to them). Create a new userRole and fill it with the database values and then add it to the empty list you created above then you can return it however you want(usersRoles) and display it as IENumerable in your view and display the roles as Role.

       foreach (var user in users)

        {
            var roles = await _userManager.GetRolesAsync(user);

            var role = roles.FirstOrDefault();

            if(!string.IsNullOrEmpty(role))
            {
               var usersRole = new UsersRoles()
                {
                   UserId = user.Id,
                   Username = user.UserName,
                   Email = user.Email,
                   FirstName = user.FirstName,
                   LastName = user.LastName,
                   PhoneNumber = user.PhoneNumber,
                   Role = role
               };

                usersRoles.Add(usersRole);
            }

        }
Homovec answered 14/3, 2022 at 14:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.