My code has undergone an incredible change in order to make mutlitple checkboxes work. I did away with the formsCollection I was trying to use to loop through checked checkboxes on the View. I am using a lot of loops inside of loops both in Controller and in View and I don't care anymore about "separation of concerns" or anything modern about MVC. In MS Access you can lump a whole bunch of functions into one line which makes it unreadable but works. I always spread out the logic in order to understand it and step through it. I am probably using a sophomoric approach to this new modern world of MVC 6 but I don't care. I can move on out of the Roles crap into actually doing something with CRUD. I also don't want to piss Stephen Muecke off at all since most of my MVC knowledge is a compilation of his attention to my questions. After Googling it with Bing I found this link about checkboxes that was very simple and helpful. And most of my view was already set up. My time was spent on displaying the user's roles that were already checked. So now, I have a View and an Edit form that allows adding or removing Roles for selected user via checkboxes. Not pretty but very tasty IMHO. ("MVC6" is the name of my project, not a built in name). I did not have to use Owin dependencies. Only dependentcy I had to add was to enable session so I could send TempData["Status"] message. Everything else is right out of the "box".
View:
@using MVC6.Models
@using Microsoft.AspNet.Http
@model Microsoft.AspNet.Identity.EntityFramework.IdentityUser
@{
ViewBag.Title = "Edit User";
var roles = new MVC6Context().Roles.ToList();
var usersroles = new MVC6Context().UserRoles.ToList();
}
<ol class="breadcrumb">
<li>@Html.ActionLink("Administration", "Index", "Admin")</li>
<li>@Html.ActionLink("Users", "Index", "UserManagement")</li>
<li>Edit User</li>
</ol>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary()
@Html.HiddenFor(model => model.Id)
@Html.HiddenFor(model => model.Email)
<h3>Username:</h3>
<div class="form-control">
@Model.Email
</div>
<h3>Roles:</h3>
if (roles.Any())
{
<div >
@foreach (var role in roles)
{
bool isinrole = false;
@foreach (var ur in usersroles)
{
@if (Model.Id == ur.UserId) //usersroles returns all roles for all users
{
@if(ur.RoleId == role.Id)
{
isinrole = true;
}
}
}
@if (isinrole)
{
<input type="checkbox" name="checkRoles" value="@role.Name" checked />
@Html.Label(role.Name)
}
else
{
<input type="checkbox" name="checkRoles" value="@role.Name"/>
@Html.Label(role.Name)
}
<br/>
}
</div>
<br />
<button type="submit" class="btn btn-default">Save</button> <span style="color:red;">@if (@TempData["Status"] != null){@TempData["Status"]}</span>
}
else
{
<div class="alert alert-info" role="alert">
No roles available
</div>
}
<br />
Controller
[HttpGet]
public ActionResult Edit(string userId)
{
return View(context.Users.FirstOrDefault(u => u.Id == userId));
}
[HttpPost]
public async Task<ActionResult> Edit(string[] checkRoles, string userID)
{
var UserManager = _serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var RoleManager = _serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var allRoles = RoleManager.Roles.ToList();
var user = await UserManager.FindByIdAsync(userID);
var usersRoles = await UserManager.GetRolesAsync(user);
//LOOP THROUGH ROLES
foreach (var item in allRoles)
{
bool wasChecked = false;
//ALL CHECKBOXES THAT WERE CHECKED
foreach (var roleChecked in checkRoles)
{
if (item.Name == roleChecked)
{
wasChecked = true;
}
}
//ALL CHECKBOXES THAT WERE NOT CHECKED
if (wasChecked == false)
{
//IF USER HAS ROLE, REMOVE IT
if (await UserManager.IsInRoleAsync(user, item.Name))
{
await UserManager.RemoveFromRoleAsync(user, item.Name);
}
}
else //IF CHECK BOX CHECKED THEN ADD ROLE TO USER
{
await UserManager.AddToRoleAsync(user, item.Name);
}
}
TempData["Status"] = "Roles are updated as of <b>" + DateTime.Now.ToShortTimeString() + "</b>";
return View(user);
}
What might help another newbie like me is that the AspNetUserRoles table has 2 columns, UserId and RuleId. This is a "many-to-many" relationship. In my code above once I get all the info about the user I want to edit, and get all the user's roles from this many-to-many, then I can iterate through it to add or delete a row. Kinda same thing for the View. I know this stuff could be refactored but it is doing business as we talk. I would gladly give accepted answer to someone who even slightly refactors this (but doesn't turn it into mad scientist gobbly gook, all due respect).