We will discuss how to manage role membership i.e add or remove users from a given role using the asp.net core identity api.
On Edit role view, when Add or remove users from this role button is clicked, we want to redirect to Edit users in role view
Edit users in role view is as shown below. If you want the user to be a member of the given role, check the checkbox, otherwise leave it unchecked.
Once the Update button is clicked the data should be updated in the underlying AspNetUserRoles database table.
AspNetUserRoles identity database table
Application users are stored in AspNetUsers database table, where as roles are stored in AspNetRoles table. UserRoles i.e user to role mapping data is stored in AspNetUserRoles table.
There is a Many-to-Many relationship between AspNetUsers and AspNetRoles table. A user can be a member of many roles and a role can contain many users as it's members. This User and Role mapping data is stored in AspNetUserRoles table.
This table has just 2 columns - UserId and RoleId. Both are foreign keys. UserId column references Id column in AspNetUsers table and RoleId column references Id column in AspNetRoles table.
UserRoleViewModel Class
HttpPost EditUsersInRole Action
EditUsersInRole View
On Edit role view, when Add or remove users from this role button is clicked, we want to redirect to Edit users in role view
<div class="card-footer">
<a asp-controller="Administration" asp-action="EditUsersInRole"
asp-route-roleId="@Model.Id" class="btn btn-primary">
Add or remove users from this role
</a>
</div>
Edit users in role view is as shown below. If you want the user to be a member of the given role, check the checkbox, otherwise leave it unchecked.
Once the Update button is clicked the data should be updated in the underlying AspNetUserRoles database table.
AspNetUserRoles identity database table
Application users are stored in AspNetUsers database table, where as roles are stored in AspNetRoles table. UserRoles i.e user to role mapping data is stored in AspNetUserRoles table.
There is a Many-to-Many relationship between AspNetUsers and AspNetRoles table. A user can be a member of many roles and a role can contain many users as it's members. This User and Role mapping data is stored in AspNetUserRoles table.
This table has just 2 columns - UserId and RoleId. Both are foreign keys. UserId column references Id column in AspNetUsers table and RoleId column references Id column in AspNetRoles table.
UserRoleViewModel Class
public class UserRoleViewModel
{
public string UserId { get; set; }
public string UserName { get; set; }
public bool IsSelected { get; set; }
}
- In the UserRoleViewModel class, in addition to UserId property, we have UserName and IsSelected properties.
- UserName property is required so we can display the UserName on the view.
- IsSelected property is required to determine if the user is selected to be a member of the role.
- We could include RoleId property also in the UserRoleViewModel class, but as far as this view is concerned, there is a one-to-many relationship from Role to Users. So, in order not to repeat RoleId for each User, we will use ViewBag to pass RoleId from controller to the view.
[HttpGet]
public async Task<IActionResult> EditUsersInRole(string roleId)
{
ViewBag.roleId = roleId;
var role = await roleManager.FindByIdAsync(roleId);
if (role == null)
{
ViewBag.ErrorMessage = $"Role with Id = {roleId} cannot be found";
return View("NotFound");
}
var model = new List<UserRoleViewModel>();
foreach (var user in userManager.Users)
{
var userRoleViewModel = new UserRoleViewModel
{
UserId = user.Id,
UserName = user.UserName
};
if (await userManager.IsInRoleAsync(user, role.Name))
{
userRoleViewModel.IsSelected = true;
}
else
{
userRoleViewModel.IsSelected = false;
}
model.Add(userRoleViewModel);
}
return View(model);
}
HttpPost EditUsersInRole Action
[HttpPost]
public async Task<IActionResult> EditUsersInRole(List<UserRoleViewModel> model, string roleId)
{
var role = await roleManager.FindByIdAsync(roleId);
if (role == null)
{
ViewBag.ErrorMessage = $"Role with Id = {roleId} cannot be found";
return View("NotFound");
}
for (int i = 0; i < model.Count; i++)
{
var user = await userManager.FindByIdAsync(model[i].UserId);
IdentityResult result = null;
if (model[i].IsSelected && !(await userManager.IsInRoleAsync(user, role.Name)))
{
result = await userManager.AddToRoleAsync(user, role.Name);
}
else if (!model[i].IsSelected && await userManager.IsInRoleAsync(user, role.Name))
{
result = await userManager.RemoveFromRoleAsync(user, role.Name);
}
else
{
continue;
}
if (result.Succeeded)
{
if (i < (model.Count - 1))
continue;
else
return RedirectToAction("EditRole", new { Id = roleId });
}
}
return RedirectToAction("EditRole", new { Id = roleId });
}
EditUsersInRole View
@model List<UserRoleViewModel>
@{
var roleId = ViewBag.roleId;
}
<form method="post">
<div class="card">
<div class="card-header">
<h2>Add or remove users from this role</h2>
</div>
<div class="card-body">
@for (int i = 0; i < Model.Count; i++)
{
<div class="form-check m-1">
<input type="hidden" asp-for="@Model[i].UserId" />
<input type="hidden" asp-for="@Model[i].UserName" />
<input asp-for="@Model[i].IsSelected" class="form-check-input" />
<label class="form-check-label" asp-for="@Model[i].IsSelected">
@Model[i].UserName
</label>
</div>
}
</div>
<div class="card-footer">
<input type="submit" value="Update" class="btn btn-primary"
style="width:auto" />
<a asp-action="EditRole" asp-route-id="@roleId"
class="btn btn-primary" style="width:auto">Cancel</a>
</div>
</div>
</form>
No comments:
Post a Comment