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

Rras
  • 163
  • 1
  • 1
  • 9
  • `context.Users` should have `Roles` property for each `user`: `var usersWithRoles = context.Users.Select(x => new UserWithRolesViewModel {User = x, UserRoles = x.Roles}).ToList();` – Dmitry Pavliv Jan 03 '15 at 20:12
  • Which namespace should i add in the View of this actionResult Method? – Rras Jan 03 '15 at 20:46
  • and what is 'UserWithRolesViewModel' after new keyword ? I am sorry for asking such silly things but i am new in MVC development – Rras Jan 03 '15 at 20:57

5 Answers5

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>
Imran Rashid
  • 1,328
  • 14
  • 21
  • 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. – Rras Jan 03 '15 at 23:56
  • 'System.Data.Entity.DynamicProxies.IdentityUserRole_3D0B060DC86D63C1E4CDDA517BFE9D83ADB0E80' this is what it is showing in Role column – Rras Jan 03 '15 at 23:57
  • 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 Users – Rras Jan 04 '15 at 00:11
  • 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?)_ – Rras Jan 04 '15 at 00:38
  • 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? – Imran Rashid Jan 04 '15 at 00:53
  • 1
    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' does not contain a definition for 'Name' and no extension method 'Name' accepting a first argument of type 'System.Collections.Generic.ICollection' could be found (are you missing a using directive or an assembly reference?)` – Rras Jan 04 '15 at 01:03
  • That is because Roles is a collection of objects (role) that has a property of Name. I have updated the code to reflect that. – Imran Rashid Jan 04 '15 at 12:15
  • Oh alright, I got it, Its working perfectly fine now. Jazakallah, May allah reward u for this kind and detailed help :) – Rras Jan 04 '15 at 13:42
  • could you please give some guidance on my question http://stackoverflow.com/questions/27784211/display-list-of-data-on-the-basis-of-roles-in-mvc-asp-net-identity?noredirect=1#comment43979675_27784211 (somewhat related to Display list of data on the basis of Roles), Thank you! – Rras Jan 05 '15 at 19:03
  • 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. – Evonet Apr 09 '16 at 13:22
  • 10
    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. – Ege Ersoz May 14 '16 at 02:29
  • 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? – megamaiku Oct 05 '17 at 18:00
  • this is still wrong. cannot access `Name` property – ELOL Jul 01 '22 at 19:55
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)
                     });
Zahir Firasta
  • 533
  • 6
  • 12
  • Thank you Zahir, your answer is really helpful. :) – SadikAli Sep 15 '17 at 05:18
  • 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? – 20B2 Oct 06 '17 at 09:27
  • @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 roles – Zahir Firasta Oct 09 '17 at 11:35
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>
  • 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. – Detilium Mar 03 '17 at 21:48
  • This should be the answer. I have looked for this for 2 weeks. – Victor Ighalo Jul 21 '19 at 09:44
  • I guess I have a knowledge gap in using LINQ. Can you point me in a direction where I can learn LINQ queries? – Victor Ighalo Jul 21 '19 at 10:05
  • 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. – devklick Aug 23 '22 at 09:16
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>
Ad Kahn
  • 551
  • 4
  • 6
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);
            }

        }
Pistone Sanjama
  • 489
  • 1
  • 4
  • 14