如何在 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
)的角色集合,其中仅包含RoleId
和UserId
。
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
只有 Roles
和 Users
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 中创建角色
从 MVC 迁移到 ASP.NET Core 3.1 中的端点路由时,具有角色的 AuthorizeAttribute 不起作用