如何在 ASP.NET MVC 5 中列出具有角色名称的用户

Posted

技术标签:

【中文标题】如何在 ASP.NET MVC 5 中列出具有角色名称的用户【英文标题】:How to list users with role names in ASP.NET MVC 5 【发布时间】:2015-02-05 12:09:58 【问题描述】:

我有 ASP.NET MVC 5 网站的默认项目模板,我正在尝试列出所有具有角色名称(而不是 ID)的用户。

查询是:

db.Users.Include(u => u.Roles).ToList()

然后我想用类似这样的方式打印角色名称:

@string.Join(", ", user.Roles.Select(r => r.RoleId))

问题是我只能访问RoleId,而不是存储Name 和其他属性的角色类。

我可以运行另一个选择来获取所有角色,然后将其用作查找。还是直接在查询中写一个join?我不知道怎么做,因为我无法访问带有将用户和角色绑定在一起的 IdentityUserRole 实体的表。

问题的根源似乎是IdentityUserRole(不是Role)的角色集合,其中仅包含RoleIdUserId

public class IdentityUserRole<TKey> 
    public virtual TKey RoleId  get; set; 
    public virtual TKey UserId  get; set; 

我认为如果想在 EF 中建立 N 对 N 关系,他们应该直接收集 Roles,然后覆盖 OnModelCreating 并指定关系。这种方法似乎使从一个对象浏览到另一个对象变得复杂。

为什么他们决定将IdentityUserRole 作为额外实体包含在内?为了能够向关系添加额外的数据?以无法从用户导航到角色为代价?

【问题讨论】:

您可以轻松地从用户导航到角色,连接表就在那里,因为存在多对多关系。我不认为身份团队只是为了好玩而制作垃圾系统.... @No1_Melman 您能否提供一个查询示例(也许作为答案)?谢谢。 给我一分钟 【参考方案1】:

我的做法是:

using (var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationContext()))

    var rolesForUser = await userManager.GetRolesAsync(userId);

   // rolesForUser now has a list role classes.

身份团队设置了两个经理:RoleManager 用于分类角色(虽然不是用户角色),UserManager 基本上用于所有身份验证。还有一个SignInManager,但不是必需的。

所以UserManager 查找用户、创建用户、删除用户、发送电子邮件....这样的例子不胜枚举。

所以我的Action 可能看起来像这样:

    public async Task<ActionResult> GetRolesForUser(string userId)
    
        using (
            var userManager =
                new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
        
            var rolesForUser = await userManager.GetRolesAsync(userId);

            return this.View(rolesForUser);
        
    

要执行原始 SQL,您可以执行以下操作:

根据查询的输出创建实体框架可以映射到的类:

public class UserWithRole

    public string UserName get;set; // You can alias the SQL output to give these better names
    public string Name get;set;


using (var context = new DbContext())

    var sql = @"
                SELECT AspNetUsers.UserName, AspNetRoles.Name 
                FROM AspNetUsers 
                LEFT JOIN AspNetUserRoles ON  AspNetUserRoles.UserId = AspNetUsers.Id 
                LEFT JOIN AspNetRoles ON AspNetRoles.Id = AspNetUserRoles.RoleId
                WHERE AspNetUsers.Id = @Id";
    var idParam = new SqlParameter("Id", theUserId);

    var result = context.Database.ExecuteQuery<UserWithRole>(sql, idParam);

很简单!

如果您为 SQL 返回列添加别名:

SELECT AspNetUSers.UserName, AspNetRoles.Name As RoleName

那么你的 DTO 类可以如下所示:

public class UserWithRole

    public string UserName get;set;
    public string RoleName get;set;

这显然要干净得多。

【讨论】:

感谢您的回答,但您从哪里获得 UserRoles DbSet?默认情况下 IdentityDbContext 只有 RolesUsers DbSets,这使得我无法进行这样的连接。 是的,我只是启动了一个项目来看看,但发现什么都没有,这很奇怪,因为在我所有的项目中我都这样做,但我想我找到了原因! 我明白了,所以没有“好”的方式来进行单个查询。我必须列出用户,然后分别查询每个用户的角色,对吗?我不知道为什么它如此“复杂”。 是的,你会分开做。但是,从速度的角度来看,去数据库并检索所有具有相关角色的用户并不是一个好兆头。在网页中,您可能希望每次用户请求时都发出 AJAX 请求。 如果您发布 SQL 以实现您想要的,那么我可以向您展示如何从 EF 执行它! @NightElfik【参考方案2】:

这就是我使用 MVC 5、Identity 2.0 和 John Atten 描述的自定义用户和角色的方式

在控制器中

public virtual ActionResult ListUser()
                
        var users = UserManager.Users;
        var roles = new List<string>();
        foreach (var user in users)
        
            string str = "";
            foreach (var role in UserManager.GetRoles(user.Id))
            
                str = (str == "") ? role.ToString() : str + " - " + role.ToString();
            
            roles.Add(str);
        
        var model = new ListUserViewModel() 
            users = users.ToList(),
            roles = roles.ToList()
        ;
        return View(model);
    

在 ViewModel 中

public class ListUserViewModel

    public IList<YourAppNamespace.Models.ApplicationUser> users  get; set; 
    public IList<string> roles  get; set; 

在我看来

@
    int i = 0;

@foreach (var item in Model.users)
   
    @html.DisplayFor(modelItem =>  item.Name)
    [... Use all the properties and formating you want ... and ] 
    @Model.roles[i]
    i++;

【讨论】:

【参考方案3】:

感谢@Callum Linington 的回答。试着让像我这样的初学者清楚一点。 以下是获取用户及其角色列表的步骤。

1- 创建一个名为“UsersWithRoles”的视图模型,其中包含如下所示的一些属性:

2- 创建一个名为“RolesController”的控制器,然后在其中添加以下代码。

        public ActionResult Index()
    
        using (var context = new ApplicationDbContext())
        
            var sql = @"
            SELECT AspNetUsers.UserName, AspNetRoles.Name As Role
            FROM AspNetUsers 
            LEFT JOIN AspNetUserRoles ON  AspNetUserRoles.UserId = AspNetUsers.Id 
            LEFT JOIN AspNetRoles ON AspNetRoles.Id = AspNetUserRoles.RoleId";
            //WHERE AspNetUsers.Id = @Id";
            //var idParam = new SqlParameter("Id", theUserId);

            var result = context.Database.SqlQuery<UserWithRoles>(sql).ToList();
            return View(result);
        

    

这就是 RolesController 的样子:

3- 将索引页面添加到角色文件夹,并在其中添加以下代码。

@model IEnumerable<MVC_Auth.ViewModels.UserWithRoles>
<div class="row">
    <h4>Users</h4>
    <table class="table table-hover table-responsive table-striped table-bordered">
        <th>User Name</th>
        <th>Role</th>
        @foreach (var user in Model)
        
            <tr>
                <td>@user.UserName</td>
                <td>@user.Role</td>
            </tr>
        
    </table>
</div>

这是结果

谢谢。

【讨论】:

【参考方案4】:

我认为从 C# 应用程序执行动态 SQL 的技术不好。下面是我的方法:

型号:

  public class ApplicationRole : IdentityRole
  
    public ApplicationRole() : base()  
    public ApplicationRole(string name) : base(name)  
    public string Description  get; set; 

  

控制器:

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Collections.Generic;

//Example for Details.
if (id == null)
  
    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
  
  var role = await RoleManager.FindByIdAsync(id);
  // Get the list of Users in this Role
  var users = new List<ApplicationUser>();

  // Get the list of Users in this Role
  foreach (var user in UserManager.Users.ToList())
  
    if (await UserManager.IsInRoleAsync(user.Id, role.Name))
    
      users.Add(user);
    
  

  ViewBag.Users = users;
  ViewBag.UserCount = users.Count();
  return View(role);

查看(使用 ApplicationRole)

    <div>
        <h4>Roles.</h4>
        <hr />
        <dl class="dl-horizontal">
            <dt>
                @Html.DisplayNameFor(model => model.Name)
            </dt>
            <dd>
                @Html.DisplayFor(model => model.Name)
            </dd>
        </dl>
        <dl class="dl-horizontal">
            <dt>
                @Html.DisplayNameFor(model => model.Description)
            </dt>
            <dd>
                @Html.DisplayFor(model => model.Description)
            </dd>
        </dl>
    </div>
    <h4>List of users in this role</h4>
    @if (ViewBag.UserCount == 0)

        <hr />
        <p>No users found in this role.</p>

    <table class="table">
        @foreach (var item in ViewBag.Users)
    
            <tr>
                <td>
                    @item.UserName
                </td>
            </tr>
    
    </table>

【讨论】:

【参考方案5】:
using System.Linq;
using System.Data;
using System.Data.Entity;

            var db = new ApplicationDbContext();
            var Users = db.Users.Include(u => u.Roles);

            foreach (var item in Users)
            
                string UserName = item.UserName;
                string Roles = string.Join(",", item.Roles.Select(r=>r.RoleId).ToList());
            

【讨论】:

以上是关于如何在 ASP.NET MVC 5 中列出具有角色名称的用户的主要内容,如果未能解决你的问题,请参考以下文章

在 Asp.net Identity MVC 5 中创建角色

在 asp.net mvc 5 中使用身份自定义用户和角色

ASP.Net MVC 5 - 使用角色授权错误

从 MVC 迁移到 ASP.NET Core 3.1 中的端点路由时,具有角色的 AuthorizeAttribute 不起作用

如何在 ASP.NET MVC 中手动设置用户角色?

如何使用 asp.net mvc 从头开始​​添加用户角色