问题
I’m in the process of learning MVC with Identity 2 and I’m at the point of taking a sample project and tweaking it to fit a site that I’m trying to convert from WebForms with ASP.Net Membership provider.
What I’m having issues with at the moment is getting my head wrapped around how I get a value from another table to populate a property in a class.
I have a class called AppUser.cs and it inherits from IdentityUser. That is basically mapped to a table named “AspNetUsers” using EntityFramework. I’ve added a couple more properties (First/Last Name) to that table using EF migrations. Now I want to display what Role the user is assigned to and eventually will need to get a list of the available roles and add them to a dropdownlist. I added the RoleName property to my AppUser class but I’m assuming that since that data is not stored in the AspNetUsers table is why I’m getting an error “Invalid column name 'RoleName'”.
How would I populate the Role and/or get a list of available Roles in my AppUser class so I can display it in my View?
public class AppUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string RoleName { get; set; }
}
The model on the view “Index.cshtml” is the AppUser.
@model IEnumerable<AppUser>
This is my ActionResult for my Controller.
public ActionResult Index() {
return View(UserManager.Users);
}
private AppUserManager UserManager {
get {
return HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
}
}
This is the AppUserManager.cs
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using SampleMvcSite.Models;
namespace SampleMvcSite.Infrastructure {
public class AppUserManager : UserManager<AppUser> {
public AppUserManager(IUserStore<AppUser> store)
: base(store) {
}
public static AppUserManager Create(
IdentityFactoryOptions<AppUserManager> options,
IOwinContext context) {
AppIdentityDbContext db = context.Get<AppIdentityDbContext>();
AppUserManager manager = new AppUserManager(new UserStore<AppUser>(db));
manager.PasswordValidator = new CustomPasswordValidator {
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = false,
RequireLowercase = true,
RequireUppercase = true
};
manager.UserValidator = new CustomUserValidator(manager) {
AllowOnlyAlphanumericUserNames = true,
RequireUniqueEmail = true
};
return manager;
}
}
}
UPDATED CODE: I ended up creating a class called UserEditViewModel and I'm also including the AppRole class which was in the sample project I'm tweaking.
public class UserEditViewModel : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserRole { get; set; }
public IEnumerable<AppRole> AllRoles { get; set; }
}
public class AppRole : IdentityRole {
public AppRole() : base() { }
public AppRole(string name) : base(name) { }
}
Then in my controller I did the following. Keep in mind I'm only going to allow a user to be assigned to one role at a time so theoretically there should only be the one role which is why I only called on the userRoles[0]. Since I added the RoleManager after some sample users I have a couple users that aren't assigned to a Role. I added a check to make sure the Roles had a count and if not I display "User" as their role. I will go back and add code to actually add the user to the "User" role if no roles are found.
List<UserEditViewModel> UserList = new List<UserEditViewModel>();
var users = UserManager.Users;
foreach (AppUser user in users)
{
var userRoles = await UserManager.GetRolesAsync(user.Id);
string roleName = userRoles.Count() == 0 ? "User" : userRoles[0];
UserEditViewModel editUser = new UserEditViewModel();
editUser.UserName = user.UserName;
editUser.FirstName = user.FirstName;
editUser.LastName = user.LastName;
editUser.Email = user.Email;
editUser.UserRole = roleName;
editUser.AllRoles = RoleManager.Roles;
UserList.Add(editUser);
}
return View(UserList);
Here is the View
<div class="form-group">
<label>Role:</label> @Html.DisplayNameFor(model => model.UserRole)
</div>
回答1:
I would look at ViewModels. It's generally bad practice to update an entity model in your view - especially security related entities. See https://www.stevefenton.co.uk/2013/03/Why-You-Never-Expose-Your-Domain-Model-As-Your-MVC-Model/
With a viewmodel, you could have a property for List<Role> that you populate in your controller and use in your view and another property like RoleId for the user's role.
In the POST you would do something like:
if (ModelState.IsValid)
{
var roleMgr = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
var userMgr = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var role = roleMgr.FindById(viewmodel.RoleId);
if (role != null) userMgr.AddToRole(viewmodel.UserId, role.Name);
}
VIEW:
<div class="form-group">
@Html.LabelFor(model => model.RoleId)
<div class="col-md-2">
@Html.DropDownListFor(model => model.RoleId, Model.RoleList, htmlAttributes: new { @class = "form-control" })
</div>
<div class="col-md-10 col-md-offset-2">
@Html.ValidationMessageFor(model => model.RoleId, "", new { @class = "text-danger" })
</div>
</div>
来源:https://stackoverflow.com/questions/33239337/need-understanding-on-how-to-get-display-user-role