У меня был метод EditEmployee
в AdminController
. Когда я отправляю форму редактирования, отображается ошибка 404. Кажется, метод не распознает EmployeeId
, я привязываю, но не могу понять.
[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);
}
и это мое мнение:
@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>
Я также попробовал другой подход, используя IFormCollection
, но он тоже не сработал:
[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();
}
}
В обоих случаях метод EditEmployee
, похоже, не обновляет данные сотрудника правильно, и я не понимаю, почему. Символ ModelState
недействителен, но я не могу определить, что его вызывает.
Может ли кто-нибудь помочь мне понять, что я делаю неправильно? Любые предложения или улучшения будут с благодарностью приняты. Я новичок в ASP.NET Core, большое спасибо.
В этой строке employee.EmployeeId = Convert.ToInt32(collection["EmployeeId"]);
вам нужна эта строка, вы должны обновить другое свойство по идентификатору, а не сам идентификатор.
Кроме того, из-за того, что EmployeeId
не включен в форму как скрытое поле. Без него значение «EmployeeId» не будет отправлено обратно на сервер, что приведет к несоответствию между параметром id и свойством «EmployeeId» объекта «Сотрудник». Это может вызвать ошибку 404, которую вы видите.
Вам нужно будет добавить эту строку <input type = "hidden" asp-for = "EmployeeId" />
в представление редактирования внутри элемента.
Большое вам спасибо, я добавил <input type = "hidden" asp-for = "EmployeeId" /> и изменил метод EditEmployee, чтобы он использовал IFormCollection и извлекал свойства сотрудника из коллекции. Это помогает обновлять другие свойства без редактирования идентификатора сотрудника.
Я также предоставил вам обновленный код, который вы можете протестировать. Убедитесь, что вы правильно заменили их в своем проекте.
Если вы хотите сделать что-то подобное, заставьте его выбрать идентификатор из маршрута, а затем передать модель, это намного проще. У вас действительно должен быть DTO (объект передачи данных) для обеспечения безопасности, чтобы вы не взаимодействовали напрямую с сущностями или людьми, которые потенциально могут играть. Но, игнорируя часть DTO, это должно сработать для вас. [HttpPost("{id:int}", Name = nameof(EditEmployee))] public async Task<IActionResult> EditEmployee([FromRoute] int id, [FromBody] Сотрудник сотрудникМодель)
В обоих случаях метод EditEmployee, похоже, не обновляет данные о сотруднике указаны правильно, и я не понимаю, почему. ModelState — это недействителен, но я не могу определить, что является причиной этого
Судя по вашему общему фрагменту кода, вы получаете 404, а ваша информация Employee
не обновляется из-за отсутствия Employee.EmployeeId
в вашей форме редактирования.
Потому что, когда вы публикуете редактирование формы вашего контроллера, ожидая Employee.EmployeeId
, который не был передан из вашего запроса на публикацию, состояние вашей модели становится ложным.
Чтобы это исправить, вам следует включить следующий код в форму редактирования.
<input type = "hidden" asp-for = "EmployeeId" />
Обновленный код должен быть:
Вид:
@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>
Контроллер:
[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);
}
Выход:
Примечание. Я протестировал сценарий с объектом класса, но если вы используете IFormCollection
, не стесняйтесь менять свойство на своем контроллере.
Рад помочь вам в этом.
Вы проверили, какое значение вы получаете в контроллере, а какое не совпадает? Если привязка модели не совпадает, она всегда будет ложной.