Как указать пользователей с именами ролей в ASP.NET MVC 5
У меня есть шаблон проекта по умолчанию веб-сайта ASP.NET MVC 5, и я пытаюсь перечислить всех пользователей с именами ролей (не идентификаторами).
Запрос:
db.Users.Include(u => u.Roles).ToList()
Затем я хочу напечатать имена ролей с чем-то вроде:
@string.Join(", ", user.Roles.Select(r => r.RoleId))
Проблема в том, что я могу достичь только RoleId
, а не класса ролей, где хранятся Name
и другие свойства.
Я могу запустить другой выбор, чтобы получить все роли, а затем использовать его в качестве поиска. Или просто написать соединение в запросе? Я не уверен, потому что у меня нет доступа к таблице с IdentityUserRole
сущностями, которые связывают пользователей и роли вместе.
Корень проблемы, по-видимому, является тем, что представляет собой набор ролей IdentityUserRole
(не Role
), который содержит только RoleId
и UserId
.
public class IdentityUserRole<TKey> {
public virtual TKey RoleId { get; set; }
public virtual TKey UserId { get; set; }
}
Я думал, что если кто-то хочет выполнить отношения N-to-N в EF, они должны поместить непосредственно коллекцию Roles
, а затем переопределить OnModelCreating
и указать отношения. Этот подход, похоже, затрудняет просмотр объектов друг от друга.
Почему они решили включить IdentityUserRole
в качестве дополнительной сущности? Уметь добавлять дополнительные данные в отношения? За счет того, что вы не можете перемещаться от пользователей к ролям?
Ответы
Ответ 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, вы можете сделать что-то вроде этого:
Создайте класс, на который может преобразовываться Entity Framework, на основе вывода вашего запроса:
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;}
}
Это, очевидно, намного чище.
Ответ 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
Я думаю, что его плохая техника для выполнения динамического 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>
Ответ 4
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());
}
Ответ 5
Спасибо @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>