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.
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
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));
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.
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)
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
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