Reputation: 10208
There is a screen in our application that allows members of the Administrators role to edit user account details.
Ultimately any user object is sent to the server and updated using:
await userManager.UpdateAsync(user);
This is working as expected for updating user records. We can make changes that are persisted to the database such as usernames, phone numbers etc.
The issue I'm seeing is that when updating the Roles sometimes rather than adding an additional role to the user it removes all the roles.
On our ApplicationUser
object we have a property like this:
public virtual ICollection<IdentityUserRole<string>> Roles { get; set; } = new List<IdentityUserRole<string>>();
So we can bounce roles between client and server as part of a user object.
What I'm struggling to understand is the inconsistent behavior of the userManager.UpdateAsync(user);
method I'm seeing. It clearly works or it would never be capable of adding any role to a user.
The object arriving at the server is correctly populated with the roles each time it is submitted. The basic flow is:
How can I prevent it from removing roles?
Thanks!
UPDATE
As detailed in the answer from @amirani I've tried filtering the existing list instead. I've setup AutoMapper
to ignore the property entirely.
.ForMember(x => x.Roles, opt => opt.Ignore());
And am now just filtering like this (only adding at the moment):
foreach (var userDtoRole in userDto.Roles)
{
if (user.Roles.FirstOrDefault(x => x.RoleId == userDtoRole) == null)
{
user.Roles.Add(new IdentityUserRole<string> {RoleId = userDtoRole, UserId = user.Id });
}
}
The additional roles are never added to the underlying database. I've confirmed that the user object being updated has the correct list of roles prior to executing the UpdateUser
method.
Upvotes: 11
Views: 2333
Reputation: 29976
Try code below to add new roles
private readonly ApplicationDbContext _context;
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public HomeController(ApplicationDbContext context
, UserManager<ApplicationUser> userManager
, RoleManager<IdentityRole> roleManager)
{
_context = context;
_userManager = userManager;
_roleManager = roleManager;
}
public async Task<IActionResult> CreateUserAndRole()
{
await _userManager.CreateAsync(new ApplicationUser { UserName = "[email protected]", Email = "[email protected]" });
await _roleManager.CreateAsync(new IdentityRole { Name = "Admin" });
await _roleManager.CreateAsync(new IdentityRole { Name = "Administrator" });
return Ok();
}
public async Task<IActionResult> AddAdminRoleToUser()
{
ApplicationUser user = _context.Users.FirstOrDefault(u => u.UserName == "[email protected]");
var role = await _roleManager.FindByNameAsync("Admin");
user.Roles.Add(new IdentityUserRole<string> { RoleId = role.Id, UserId = user.Id });
await _userManager.UpdateAsync(user);
return Ok();
}
public async Task<IActionResult> AddAdministratorRoleToUser()
{
ApplicationUser user = _context.Users.FirstOrDefault(u => u.UserName == "[email protected]");
var role = await _roleManager.FindByNameAsync("Administrator");
user.Roles.Add(new IdentityUserRole<string> { RoleId = role.Id, UserId = user.Id });
await _userManager.UpdateAsync(user);
return Ok();
}
Upvotes: 1
Reputation: 270
When you call await userManager.UpdateAsync(user);
You are updating user model with all its related data. You need to add new role to an existing roles list instead of creating new empty list and adding new record.
Upvotes: 2