2014-12-07 10 views
10

Ho un modello di progetto predefinito del sito Web ASP.NET MVC 5 e sto cercando di elencare tutti gli utenti con nomi di ruolo (non ID).Come elencare gli utenti con nomi di ruolo in ASP.NET MVC 5

La query è:

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

poi voglio stampare i nomi dei ruoli con qualcosa di simile:

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

Il problema è che posso raggiungere solo RoleId, non di classe Ruolo dove Name e altre proprietà sono memorizzate.

Potrei eseguire un'altra selezione per ottenere tutti i ruoli e quindi utilizzarla come ricerca. O scrivi direttamente un join nella query? Non so come, perché non ho accesso alla tabella con le entità IdentityUserRole che uniscono utenti e ruoli.

La radice del problema sembra essere il fatto che è ruoli raccolta di IdentityUserRole (non Role) che contiene solo RoleId e UserId.

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

ho pensato che se uno vuole fare rapporto N-per-N in EF dovrebbero mettere direttamente collezione di Roles e poi ignorare OnModelCreating e specificare le relazioni. Questo approccio sembra complicare la navigazione degli oggetti da uno all'altro.

Perché hanno deciso di includere IdentityUserRole come entità extra? Per essere in grado di aggiungere dati extra alle relazioni? Al costo di non essere in grado di navigare dagli utenti ai ruoli?

+0

puoi facilmente passare da utente a ruolo, la tabella di join è lì perché c'è una relazione molti a molti. Non penso che il team di Identity crei un sistema di spazzatura per il divertimento .... –

+0

@ No1_Melman Potrebbe includere un esempio della query (forse come risposta)? Grazie. – NightElfik

+0

Sì, dammi un minuto –

risposta

14

Il modo in cui lo faccio è:

using (var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationContext())) 
{ 
    var rolesForUser = await userManager.GetRolesAsync(userId); 

    // rolesForUser now has a list role classes. 
} 

Il team di identità ha fatto due gestori: RoleManager per l'ordinamento ruoli (non ruoli utente però) e UserManager fondamentalmente per l'autenticazione tutto saggio. C'è anche un SignInManager ma non è necessario.

Quindi UserManager trova utenti, crea utenti, elimina utenti, invia e-mail .... la lista continua.

Quindi il mio Action potrebbe assomigliare a questo:

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); 
     } 
    } 

Per eseguire SQL prime allora si può fare qualcosa di simile:

Creare la classe che Entity Framework può mappare, in base alla produzione di La tua richiesta:

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); 
} 

Abbastanza semplice!

Se pseudonimo Il tuo SQL colonne di ritorno:

SELECT AspNetUSers.UserName, AspNetRoles.Name As RoleName 

Poi la classe DTO può apparire come segue:

public class UserWithRole 
{ 
    public string UserName {get;set;} 
    public string RoleName {get;set;} 
} 

che è ovviamente molto più pulito.

+0

Grazie per la risposta, ma dove hai ottenuto il DbSet 'UserRoles'? In default 'IdentityDbContext' ci sono solo' Roles' e 'Users' DbSets che rendono impossibile l'unione ai miei occhi. – NightElfik

+0

Sì, ho appena creato un progetto per dare un'occhiata, ma ho scoperto che non c'era niente, che è bizzarro, perché in tutti i miei progetti lo faccio, ma penso di averne trovato il motivo! –

+0

@NightElfik vedere ora! –

0

Penso che sia una cattiva tecnica per eseguire SQL dinamico dall'applicazione C#. Qui di seguito è il mio metodo:

Modello:

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

    } 

Controller:

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); 

View (usando 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> 
3

Ecco come lo faccio con MVC 5, Identità 2.0 e un utente e un ruolo personalizzati descritti da John Atten

controller

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); 
    } 

In ViewModel

public class ListUserViewModel 
{ 
    public IList<YourAppNamespace.Models.ApplicationUser> users { get; set; } 
    public IList<string> roles { get; set; } 
} 

ea mio parere

@{ 
    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++; 
} 
0
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()); 
      } 
0

Grazie a @Callum Linington per la sua risposta. Cerca di renderlo un po 'più chiaro per i principianti come me. Ecco i passaggi per ottenere un elenco di utenti con i loro ruoli.

1- creare un modello di vista chiamata "UsersWithRoles" con alcune proprietà come illustrato di seguito:

enter image description here

2- Creare un controller chiamato "RolesController", e quindi aggiungere seguente pezzo di codice in esso.

 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); 
     } 

    } 

e qui è ciò che il RolesController dovrebbe essere simile:

enter image description here

3- Aggiungi pagina Indice nella cartella Ruoli, e aggiungere il seguente codice in esso.

@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>

Ecco il risultato

enter image description here

Grazie.

Problemi correlati