【问题标题】:How to list users with role names in ASP.NET MVC 5如何在 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 您能否提供一个查询示例(也许作为答案)?谢谢。
  • 给我一分钟

标签: c# asp.net-mvc-5 entity-framework-6 asp.net-identity-2


【解决方案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());
                    }
        

        【讨论】:

          猜你喜欢
          • 2014-09-16
          • 1970-01-01
          • 1970-01-01
          • 2015-09-01
          • 1970-01-01
          • 2017-07-25
          • 2019-08-22
          • 2013-08-06
          • 1970-01-01
          相关资源
          最近更新 更多