MVC Asp.net身份验证中具有角色的用户列表

13

我希望能够得到注册在我的网站上的所有用户及其角色清单。

Id | 名称 | 角色


1 | ABC | 管理员


2 | DEF | 用户

像这样,我已经创建了一个角色控制器,其中列出了所有角色。

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

在视图中

@model IEnumerable<Microsoft.AspNet.Identity.EntityFramework.IdentityRole>
@{
    ViewBag.Title = "Index";
}    
<div>
    @foreach (var role in Model)
    {
        <p>
            <strong>@role.Name | </strong>
        </p>
    }
</div>
这将列出所有角色,但我想要用户列表及其角色。
请提供任何解决方案,谢谢。

context.Users 应该为每个 user 拥有一个 Roles 属性: var usersWithRoles = context.Users.Select(x => new UserWithRolesViewModel {User = x, UserRoles = x.Roles}).ToList(); - Dmitry Pavliv
这个 actionResult 方法的视图中应该添加哪个命名空间? - Rras
在new关键字后面的'UserWithRolesViewModel'是什么?很抱歉问这样愚蠢的问题,但我是MVC开发的新手。 - Rras
5个回答

12
创建一个名为UserViewModel的新类。这将作为您页面的视图模型。
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;}
}
在控制器的动作方法中,获取用户及其角色列表,并将其映射到 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);
}

然后在视图中使用新模型。确保在此处使用正确的命名空间,这是您定义视图模型的位置。

@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>

这是在角色列中显示的内容:'System.Data.Entity.DynamicProxies.IdentityUserRole_3D0B060DC86D63C1E4CDDA517BFE9D83ADB0E80'。 - Rras
是的,应该使用Roles而不是Role,但这会引出一个问题:如果用户同时属于“用户”和“管理员”角色,你会怎么做? - Imran Rashid
1
如果一个用户同时是管理员和普通用户,则该用户会同时被列在管理员和普通用户中。在更正为“角色”后,出现了错误,因为无法访问名称,错误提示为:“System.Collections.Generic.ICollection<Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole>”不包含“Name”的定义,也没有找到接受类型为“System.Collections.Generic.ICollection<Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole>”的第一个参数的“Name”扩展方法(是否缺少使用指令或程序集引用?) - Rras
10
我不确定为什么这个答案被接受了。它是错误的。RolesIdentityUserRole 对象的集合,这些对象没有 Name 属性。这段代码无法运行。 - Ege Ersoz
这是一种有趣的方法。我已经花了太长时间来尝试让它工作,而这个答案却为我解决了问题...虽然我不是很喜欢查询...但它确实可行。我只是想知道随着 EF 的更新,这个答案的可靠性会如何。它应该还是有效的,对吧? - megamaiku
显示剩余9条评论

8

虽然回答这个问题已经很晚了,但是为了未来的访问者,我还是提供一下:

创建视图模型类:

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

然后在控制器中填充此视图模型类:

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

在这里,context.Users代表了AspNetUsers表,该表具有一个导航属性Roles,该属性代表AspNetUserInRoles表。然后,我们将context.Roles与代表AspNetRoles表的表进行连接以获取角色名。
现在将此列表返回到您的Index视图:
return View(userWithRoles);

在视图中展示带有角色的用户列表:
@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>

编辑:获取用户的多个角色(如果分配任何角色)

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,你的回答真的很有帮助。 :) - SadikAli
如果用户有多个角色,则会创建同一用户的多条记录。我们能否在单个列中列出分配给该用户的所有角色?此外,如果用户没有角色,则不会显示他们,如何显示未分配任何角色的用户? - 20B2
@20B2,我已更新我的答案,现在它还显示了在单个列中显示多个角色的选项(逗号分隔)。它还包括那些未被分配任何角色的用户。 - Zahir Firasta

5
我有一个如上所述的解决方案。 这是一个MVC 6中的解决方案。
在AccountViewModel.cs中添加模型。
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; }
}

控制器如下:
    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); 

    }

最后,这是景色:
@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>

这正是我一直在寻找的。我希望有更好的解决方案,因为这感觉有点“hacky”。奇怪的是,他们将Roles属性更改为IdentityUserRole列表而不是IdentityRole列表,因此我们需要按ID而不仅仅是名称进行比较,尽管使用RoleManager添加用户仍然使用角色名称而不是ID。 - Detilium
这应该是答案。我已经找了两个星期了。 - Victor Ighalo
我想我在使用LINQ方面存在知识盲区。你能指点我学习LINQ查询的方向吗? - Victor Ighalo
个人而言,我会尽可能避免使用查询式的Linq语法。在上面的代码中,当寻找FirstOrDefault时,你可以使用查询语法来实现:var role = context.Roles.FirstOrDefault(r => r.Name.Contains("Adviser"));。有时候查询式语法更好(比如用于连接),但通常我发现方法式语法更易读。我绝对不建议像上面的例子那样混合使用两种语法。 - devklick

0
这是我获取用户及其角色的解决方案:
创建一个 ViewModel 来保存用户及其角色,如下所示:
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; }
}

在控制器中:使用UserManager选择所有以下喜欢的用户,并将它们放入一个变量中。
var users = _userManager.Users.ToList();

创建一个空列表:其中之一为userRoles并给它命名 List usersRoles = new List();
循环遍历所有用户,并在循环中使用角色管理器选择所有角色,并传递用户变量。如果角色不为null或为空(您必须确保所有用户都被分配了角色),则创建一个新的userRole并填充它与数据库值,然后将其添加到您上面创建的空列表中,然后您可以按照自己的方式返回它(usersRoles)并在视图中显示为IENumerable并将角色显示为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);
            }

        }

0

我也有一个与上面类似的解决方案。这是MVC 6中的解决方案。 原因是我尝试了上面的代码并遇到了问题。所以...

让我们开始创建一个名为UserViewModel的新类。这将作为您页面的视图模型。

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

控制器如下:

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

    }

最后是视图:

@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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接