I had a EditEmployee
method in AdminController
. When I submit the edit form it display the error 404. It seem that the method don't recognize the EmployeeId
I bind but I can't figure out
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditEmployee(int id, [Bind("EmployeeId,Name,Email,Password,RoleId,ShopId")] Employee employee)
{
if (id != employee.EmployeeId)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(employee);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!_context.Employees.Any(e => e.EmployeeId == employee.EmployeeId))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
var errors = ModelState.Values.SelectMany(v => v.Errors);
foreach (var error in errors)
{
Console.WriteLine(error.ErrorMessage);
}
ViewBag.RoleId = new SelectList(_context.Roles, "RoleId", "RoleName", employee.RoleId);
ViewBag.ShopId = new SelectList(_context.RetailShops, "ShopId", "Address", employee.ShopId);
return View(employee);
}
and this is my view:
@model Nexus.Models.Employee
<div class="row">
<div class="col-md-4">
<form asp-action="EditEmployee" asp-controller="Admin" method="post">
<div class="text-danger"></div>
<div class="form-group">
<label class="control-label">Name</label>
<input asp-for="Name" class="form-control" />
<span class="text-danger" asp-validation-for="Name"></span>
</div>
<div class="form-group">
<label class="control-label">Email</label>
<input asp-for="Email" class="form-control" />
<span class="text-danger" asp-validation-for="Email"></span>
</div>
<div class="form-group">
<label class="control-label">Password</label>
<input asp-for="Password" class="form-control" />
<span class="text-danger" asp-validation-for="Password"></span>
</div>
<div class="form-group">
<label class="control-label">Role</label>
<select asp-for="RoleId" class="form-control" asp-items="ViewBag.RoleId"></select>
<span class="text-danger" asp-validation-for="RoleId"></span>
</div>
<div class="form-group">
<label class="control-label">Shop address</label>
<select asp-for="ShopId" class="form-control" asp-items="ViewBag.ShopId"></select>
<span class="text-danger" asp-validation-for="ShopId"></span>
</div>
<br />
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
</form>
</div>
I also tried another approach using IFormCollection
, but it didn't work either:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditEmployee(int id, IFormCollection collection)
{
try
{
var employee = await _context.Employees.FirstOrDefaultAsync(m => m.EmployeeId == id);
if (employee == null)
{
return NotFound();
}
employee.EmployeeId = Convert.ToInt32(collection["EmployeeId"]);
employee.Name = collection["Name"];
employee.Email = collection["Email"];
employee.Password = collection["Password"];
employee.RoleId = Convert.ToInt32(collection["RoleId"]);
employee.ShopId = Convert.ToInt32(collection["ShopId"]);
_context.Update(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
catch (DbUpdateConcurrencyException)
{
if (!_context.Employees.Any(e => e.EmployeeId == id))
{
return NotFound();
}
else
{
throw;
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
return View();
}
}
In both cases, the EditEmployee
method does not seem to update the employee details correctly, and I am not sure why. The ModelState
is invalid, but I cannot determine what is causing it.
Could someone please help me understand what I might be doing wrong? Any suggestions or improvements would be greatly appreciated. I'm new to ASP.NET Core, thank you so much.
In both cases, the EditEmployee method does not seem to update the employee details correctly, and I am not sure why. The ModelState is invalid, but I cannot determine what is causing it
Based on your shared code snippet, you are getting 404 and your Employee
informatin not updating due to the absense of Employee.EmployeeId
within your edit form.
Because when you would post edit form your controller expecting Employee.EmployeeId
which has not been passed from your from post reuqest, So your model state become false.
In order to fix that, you should inlcude following code with your edit form.
<input type="hidden" asp-for="EmployeeId" />
Updated Code should be:
View:
@model Nexus.Models.Employee
<div class="row">
<div class="col-md-4">
<form asp-action="EditEmployee" asp-controller="Admin" method="post">
<input type="hidden" asp-for="EmployeeId" />
<div class="form-group">
<label class="control-label">Name</label>
<input asp-for="Name" class="form-control" />
<span class="text-danger" asp-validation-for="Employee.Name"></span>
</div>
<div class="form-group">
<label class="control-label">Email</label>
<input asp-for="Email" class="form-control" />
<span class="text-danger" asp-validation-for="Employee.Email"></span>
</div>
<div class="form-group">
<label class="control-label">Password</label>
<input asp-for="Password" class="form-control" />
<span class="text-danger" asp-validation-for="Employee.Password"></span>
</div>
<div class="form-group">
<label class="control-label">Role</label>
<select asp-for="RoleId" class="form-control" asp-items="Model.RoleList"></select>
<span class="text-danger" asp-validation-for="Employee.RoleId"></span>
</div>
<div class="form-group">
<label class="control-label">Shop address</label>
<select asp-for="ShopId" class="form-control" asp-items="Model.ShopList"></select>
<span class="text-danger" asp-validation-for="Employee.ShopId"></span>
</div>
<br />
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
</form>
</div>
</div>
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditEmployee([Bind("EmployeeId,Name,Email,Password,RoleId,ShopId")] Employee employee)
{
var existingEmployee = _context.FirstOrDefault(e => e.EmployeeId == employee.EmployeeId);
if (existingEmployee == null)
{
return NotFound();
}
if (ModelState.IsValid)
{
existingEmployee.Name = employee.Name;
existingEmployee.Email = employee.Email;
existingEmployee.Password = employee.Password;
existingEmployee.RoleId = employee.RoleId;
existingEmployee.ShopId = employee.ShopId;
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
var viewModel = new EmployeeIndexViewModel
{
Employee = employee,
RoleList = new List<SelectListItem>
{
new SelectListItem { Value = "1", Text = "Admin" },
new SelectListItem { Value = "2", Text = "User" }
},
ShopList = new List<SelectListItem>
{
new SelectListItem { Value = "1", Text = "Shop 1" },
new SelectListItem { Value = "2", Text = "Shop 2" }
}
};
return View(viewModel);
}
Output:
Note: I have tested the scenario with the class object but if you are using IFormCollection
then feel free to change the property at your controller.