I am trying to implement roles in an EF application. I have it working on all the scaffolded views (Create, Delete, Details) but am having trouble getting the Edit view to work.
The GET method returns the data fine (as in when I go to the Edit page I see the roles correctly):
However, if I make a change and save it, I get the error:
Object reference not set to an instance of an object.
Line 47: @Html.Label("Roles", new { @class = "control-label col-md-2" })
Line 48: < span class="col-md-10" >
Line 49: @foreach (var item in Model.RolesList)
Line 50: {
Line 51: < input type="checkbox" name="SelectedRole" value="@item.Value"
checked="@item.Selected" class="checkbox-inline" />
My Get and Post methods are as follows:
//
// GET: /Users/Edit/1
public async Task<ActionResult> Edit(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var user = await UserManager.FindByIdAsync(id);
if (user == null)
{
return HttpNotFound();
}
var userRoles = await UserManager.GetRolesAsync(user.Id);
return View(new EditUserViewModel()
{
Id = user.Id,
Email = user.Email,
Username = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
RolesList = RoleManager.Roles.ToList().Select(x => new SelectListItem()
{
Selected = userRoles.Contains(x.Name),
Text = x.Name,
Value = x.Name
})
});
}
//
// POST: /Users/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "Email,Id,Username,FirstName,LastName")] EditUserViewModel editUser, params string[] selectedRole)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByIdAsync(editUser.Id);
if (user == null)
{
return HttpNotFound();
}
user.UserName = editUser.Username;
user.Email = editUser.Email;
user.FirstName = editUser.FirstName;
user.LastName = editUser.LastName;
var userRoles = await UserManager.GetRolesAsync(user.Id);
selectedRole = selectedRole ?? new string[] { };
var result = await UserManager.AddToRolesAsync(user.Id, selectedRole.Except(userRoles).ToArray<string>());
if (!result.Succeeded)
{
ModelState.AddModelError("", result.Errors.First());
return View();
}
result = await UserManager.RemoveFromRolesAsync(user.Id, userRoles.Except(selectedRole).ToArray<string>());
if (!result.Succeeded)
{
ModelState.AddModelError("", result.Errors.First());
return View();
}
return RedirectToAction("Index");
}
ModelState.AddModelError("", "Something failed.");
return View();
}
and the offending section in my View is:
<div class="form-group">
@Html.Label("Roles", new { @class = "control-label col-md-2" })
<span class="col-md-10">
@foreach (var item in Model.RolesList)
{
<input type="checkbox" name="SelectedRole" value="@item.Value" checked="@item.Selected" class="checkbox-inline" />
@Html.Label(item.Value, new { @class = "control-label" })
}
</span>
</div>
I have the rolemanager set up in my controller:
private ApplicationRoleManager _roleManager;
public ApplicationRoleManager RoleManager
{
get
{
return _roleManager ?? HttpContext.GetOwinContext().Get<ApplicationRoleManager>();
}
private set
{
_roleManager = value;
}
}
And this is in my Startup.auth:
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
I'm pretty confident the rolemanager is set up OK, as it successfully brings back the roles on the Create and Details pages. So why is
@foreach (var item in Model.RolesList)
failing with a null reference exception here?