Get list of users with assigned roles in asp.net identity 2.0
Asked Answered
L

8

33

I have a drop down list box which lists roles. I want to get the list of users having that role. I mean list of users that are in "Administrator" role or "CanEdit" role. Here is my code:

public IQueryable<Microsoft.AspNet.Identity.EntityFramework.IdentityUser> 
  GetRolesToUsers([Control] string ddlRole)
{    
  //ddlRole returns role Id, based on this Id I want to list users

  var _db = new ApplicationDbContext();
  IQueryable<Microsoft.AspNet.Identity.EntityFramework.IdentityUser> query = _db.Users;

  if (ddlRole != null)
  {
    //query = query.Where(e => e.Claims == ddlRole.Value);  ???????              
  }

  return query;
}

Please help.

Updated Code (still error)

public List<IdentityUserRole> GetRolesToUsers([Control]string ddlRole)
{

  var roleManager = 
   new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));
  var users = roleManager.FindByName("Administrator").Users.ToList();
  return users;
}

Error: The Select Method must return one of "IQueryable" or "IEnumerable" or "Microsoft.AspNet.Identity.EntityFramework.IdentityUser" when ItemType is set to "Microsoft.AspNet.Identity.EntityFramework.IdentityUser".

I tried various castings but none of them helped.

UPDATE (working solution)

Thanks to chris544, his idea helped me to fix this. Here is working method:-

public List<ApplicationUser> GetRolesToUsers([Control]string ddlRole)
{
  var context = new ApplicationDbContext();
  var users =
    context.Users.Where(x => x.Roles.Select(y => y.RoleId).Contains(ddlRole)).ToList();

  return users;
}
Lanctot answered 23/5, 2014 at 8:27 Comment(4)
Try Roles.GetUsersInRole(), you can get use default Role Provider APIPhalanstery
@Phalanstery you mean [string[] u = Roles.GetUsersInRole(ddlRole)] or [_roleManager.Roles.GetUsersInRole(ddlRole)]. First produces "The Role Manager feature has not been enabled" error and second no definition for "GetUserInRole". How I should use Roles.GetUsersInRole()?Lanctot
Are you working on asp.net mvc 5? I'm currently working on 4. go to any action method and types "Roles" and it lives within "System.Web.Security" namespace.Phalanstery
I'm using ASP.NET 4.5 and ASP.NET Identity 2.0Lanctot
C
41

Not an expert, but ...

There seemed to be no built in funcionality for this in Identity and I could not get it work from built in Roles also (it seems to not work with claims based Identity).

So I ended up doing something like this:

var users = context.Users        
    .Where(x => x.Roles.Select(y => y.Id).Contains(roleId))
    .ToList();
  • x.Roles.Select(y => y.Id) gets a list of all role ids for user x
  • .Contains(roleId) checks if this list of ids contains necessary roleId
Crispation answered 25/5, 2014 at 10:23 Comment(5)
There was no built in functionality for this in Identity 1.0, but it was expected in 2.0 somewhere on web i read this.Lanctot
Thanks chris544, your idea helped me to fix this. I updated the question and i'm sure it will help many devs.Lanctot
Been looking for an hour or so for a simple implementation. FINALLY found it. Thanks!Jemmy
If the Id of the role is not known, should use an instance of RoleManager first.Griffin
y.Id should be y.RoleIdCutinize
T
13

I find the role by the role name input. After, I find list users by id of the role.

public List<ApplicationUser> GetUsersInRole(string roleName)
{
 var roleManager = 
  new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new  ApplicationDbContext()));
 var role = roleManager.FindByName(roleName).Users.First();
 var usersInRole = 
  Users.Where(u => u.Roles.Select(r => r.RoleId).Contains(role.RoleId)).ToList();
 return usersInRole;
}
Torbart answered 19/11, 2014 at 17:4 Comment(2)
Great answer Trieu. Provided reusable code in my opinion. Short, concise, and flat out works!Gnome
I found out that @Trieu Doan was not corrent in my case, the code that worked was as following: ` var users = roleManager.FindByName(roleName).Users.Select(x => x.UserId); var usersInRole = Users.Where(u => users.Contains(u.Id));`Faires
M
7

If you want to avoid using the context directly you can use the RoleManager with the following snippet

roleManager.FindByName("Administrator").Users

or

roleManager.FindByName("CanEdit").Users

For a short discussion about this topic have a look at the this thread

Mendie answered 25/5, 2014 at 10:39 Comment(2)
Thanks Horizon_Net..looks i'm very close to solution. Please check my updated code which produce error.Lanctot
This returns a collection of IdentityUserRoles, not ApplicationUsersGriffin
H
4

Using the RoleManager gives you this solution:

if(roleManager.RoleExists("CanEdit"))
{
    var idsWithPermission = roleManager.FindByName("CanEdit").Users.Select(iur => iur.Id);
    var users = db.Users.Where(u => idsWithPermission.Contains(u.Id));
}

I'd be interested to hear if this was better or worse than the other solutions here.

Hydrops answered 1/10, 2014 at 13:2 Comment(2)
The only change I would make would be to wrap the above in an if statement to check if role exists. if(roleManager.RoleExists("CanEdit")Remunerative
+1 Going to the RoleManager (e.g. role table) is a much better shortcut than numerous LINQ queries that ultimately produce lots of SQL.Spinoza
J
4

There are three ways you can do it.

In the Controller current logged in user's role can be checked as follows,

  if(User.IsInRole("SysAdmin"))
        {

Outside Controller you can check whether a particular user belongs to a Role as follows:

 ApplicationUserManager UserManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        var roles = UserManager.GetRoles(userid);
        if (roles.Contains("SysAdmin"))
        {
        }

Do not forget to add namespace,

using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;

For some reasons like integration testing etc, you may directly want to use EF to find user's role as follows:

string userId = User.Identity.GetUserId();
        ApplicationDbContext db = new ApplicationDbContext();
        var role = (from r in db.Roles where r.Name.Contains("Admin") select r).FirstOrDefault();
        var users = db.Users.Where(x => x.Roles.Select(y => y.RoleId).Contains(role.Id)).ToList();
        if (users.Find(x => x.Id == userId) != null)
        {
            // User is in the Admin Role
        }

Hope it helps.

Thanks /dj @debug_mode

Judgeship answered 28/10, 2014 at 20:20 Comment(0)
S
0

Remove the .Email and add UserName or whatever was added to the ASPNetUsers for name.

private void AddAddminToMail(MailMessage message)
{
    var roles = db.Roles.Include(m => m.Users).Where(m => m.Name == "Admin").First();
    foreach (var user in roles.Users)
        {
            var id = user.UserId;
            var userEmail = db.Users.Find(id).Email;
            message.To.Add(userEmail);
        }      
}
Stratum answered 25/4, 2016 at 15:15 Comment(0)
P
0

the code working for me was as following:

  var users = roleManager.FindByName(roleName).Users.Select(x => x.UserId);
  var usersInRole = Users.Where(u => users.Contains(u.Id));
Parsaye answered 29/10, 2016 at 15:33 Comment(0)
W
0

Since bits like this tend to impact performance, I tried the other answers posted here and looked at the SQL they generated. This seems to be the most performant way of getting all the user's email addresses currently.

public void SendEmailToUsersInRole(string roleName)
{
    MailMessage message = new MailMessage();
    ...

    using (var usersDB = new ApplicationDbContext())
    {
        var roleId = 
            usersDB.Roles.First(x => x.Name == roleName).Id;

        IQueryable<string> emailQuery =
            usersDB.Users.Where(x => x.Roles.Any(y => y.RoleId == roleId))
                         .Select(x => x.Email);

        foreach (string email in emailQuery)
        {
            message.Bcc.Add(new MailAddress(email));
        }
    }

    ...
}

The SQL that it executes is shown below:

SELECT TOP (1) 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name]
    FROM [dbo].[AspNetRoles] AS [Extent1]
    WHERE N'Reviewer' = [Extent1].[Name]

SELECT 
    [Extent1].[Email] AS [Email]
    FROM [dbo].[AspNetUsers] AS [Extent1]
    WHERE  EXISTS (SELECT 
        1 AS [C1]
        FROM [dbo].[AspNetUserRoles] AS [Extent2]
        WHERE ([Extent1].[Id] = [Extent2].[UserId]) AND ([Extent2].[RoleId] = @p__linq__0)
    )


-- p__linq__0: '3' (Type = String, Size = 4000)
Willemstad answered 2/7, 2018 at 19:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.