I have created an Admin section of my MVC5/EF6 application. I can successfully Create() and Delete() Users, but my Edit() continues to error out on the POST.
Edit View
@model PROJECT.Models.ApplicationUser
@{
ViewBag.Title = "Edit";
Layout = "~/Areas/Admin/Views/Shared/_LayoutAdmin.cshtml";
PROJECT.Helper.GeneralHelper helper = new PROJECT.Helper.GeneralHelper();
string cancelEditUrl = "/Admin/UserManagement/";
}
@using (Html.BeginForm("Edit", "UserManagement", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
@Html.HiddenFor(model => model.Id)
@Html.HiddenFor(model => model.ForumUsername)
@Html.HiddenFor(model => model.ReceiveSystemEmails)
@Html.HiddenFor(model => model.RegisteredDate)
@Html.HiddenFor(model => model.LastVisitDate)
<div class="container">
<div class="row">
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="row">
<div class="editor-label">
@Html.LabelFor(model => model.Position)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.Position, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Position)
</div>
</div>
<div class="row">
<div class="editor-label">
@Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.Email, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Email)
</div>
</div>
<div class="row">
<div class="editor-label">
@Html.LabelFor(model => model.PhoneNumber)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.PhoneNumber, new { @class = "form-control", type = "tel" })
@Html.ValidationMessageFor(model => model.PhoneNumber)
</div>
</div>
<div class="row">
<div class="col-md-1" style="padding-left: 0px">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
<div class="col-md-9" style="padding-left: 0px">
<a href="@cancelEditUrl" class="btn btn-danger">Cancel</a>
</div>
@{
string deleteURL = "/Admin/UserManagement/Delete/" + Model.Id;
}
<a href=@deleteURL class="btn btn-danger col-md-2">
<span class="glyphicon glyphicon-minus"></span> Delete User
</a>
</div>
</div>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Controller:
// GET: Admin/UserManagement/Edit/5
public async Task<ActionResult> Edit(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ApplicationUser model = await UserManager.FindByIdAsync(id);
if (model == null)
{
return HttpNotFound();
}
return View(model);
}
// POST: Admin/UserManagement/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "Id,property1, property2, etc...")] ApplicationUser applicationUser)
{
if (ModelState.IsValid)
{
db.Entry(applicationUser).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(applicationUser);
}
When I create a user, all I have to enter is a Name
& Email
on the GUI side, such as Test User
and testuser@project.org
. When the user is created, I am returned to my Index view, where I can choose to Edit my new User. If I open my Edit View and then add a position of say Test Monkey
and click save, my Controller's POST Edit() code executes, but at await db.SaveChangesAsync();
immediately jumps down to my DB dispose():
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
and I continue from there I get the following Error Details:
Server Error in '/' Application.
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
Anyone have ideas on what may be going on? This was previously a functioning section of the project developed under MVC4/EF5 and then it was upgraded to make use of enhancements in MVC5 such as Identity.
EDIT:
Implemented an Application Trace as suggested by David Martin:
View ASP.Net Trace Information
Not quite sure what it is I am now looking for?
EDIT2:
Still not sure what I'm after exactly on the Trace, but using my breakpoint in the Catch I drilled down into [dbEx] and found the true error message was "The UserName field is required".
By adding applicationUser.UserName = applicaitonUser.Email
(which is the same thing in my current application) I am able to Edit and Save changes to my Users now.
What I can't seem to figure out however, is why this is required in the first place. As can be seen below (and I have confirmed), the User's [UserName] value is set within my POST Create() method:
// POST: Admin/UserManagement/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "Id,property1,property2,etc.,UserName")] ApplicationUser applicationUser)
{
if ((applicationUser.MemberOrgId == null) && (applicationUser.SponsorOrgId == null))
{
ModelState.AddModelError("", "Must select either an Organization or Sponsor from the dropdown lists.");
return View(applicationUser);
}
if (ModelState.IsValid)
{
ViewBag.headerTitle = "Create User";
applicationUser.UserName = applicationUser.Email;
IdentityResult result = await UserManager.CreateAsync(applicationUser, "test12345");
if (result.Succeeded)
{
await db.SaveChangesAsync();
return RedirectToAction("Index", "UserManagement");
}
else
{
ModelState.AddModelError("", "Failed to Create User.");
var errors = string.Join(",", result.Errors);
ModelState.AddModelError("", errors);
}
}
ModelState.AddModelError("", "Failed to Create User.");
var errors1 = ModelState.Where(x => x.Value.Errors.Count > 0).Select(x => new { x.Key, x.Value.Errors }).ToString();
ModelState.AddModelError("", errors1);
ViewData["Organization"] = new SelectList(db.MemberOrganizations, "Id", "Name", applicationUser.MemberOrgId);
ViewData["Sponsor"] = new SelectList(db.SponsorOrganizations, "Id", "Name", applicationUser.SponsorOrgId);
if (applicationUser.MemberOrgId != null)
{
ViewBag.SwitchState = true;
}
else
{
ViewBag.SwitchState = false;
}
ViewBag.OrganizationId = new SelectList(db.MemberOrganizations, "Id", "State", applicationUser.MemberOrgId);
// If we got this far, something failed, redisplay form
return View(applicationUser);
}
Thus, it should not be flagged as required in my POST Edit() as it has already been set?