Как указать пользователей с именами ролей в 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>