Почему мой метод редактирования не работает в ASP.NET Core

У меня был метод 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, большое спасибо.

Вы проверили, какое значение вы получаете в контроллере, а какое не совпадает? Если привязка модели не совпадает, она всегда будет ложной.

Md Farid Uddin Kiron 19.07.2024 09:24

В этой строке employee.EmployeeId = Convert.ToInt32(collection["EmployeeId"]); вам нужна эта строка, вы должны обновить другое свойство по идентификатору, а не сам идентификатор.

Md Farid Uddin Kiron 19.07.2024 09:29

Кроме того, из-за того, что EmployeeId не включен в форму как скрытое поле. Без него значение «EmployeeId» не будет отправлено обратно на сервер, что приведет к несоответствию между параметром id и свойством «EmployeeId» объекта «Сотрудник». Это может вызвать ошибку 404, которую вы видите.

Md Farid Uddin Kiron 19.07.2024 09:31

Вам нужно будет добавить эту строку <input type = "hidden" asp-for = "EmployeeId" /> в представление редактирования внутри элемента.

Md Farid Uddin Kiron 19.07.2024 09:33

Большое вам спасибо, я добавил <input type = "hidden" asp-for = "EmployeeId" /> и изменил метод EditEmployee, чтобы он использовал IFormCollection и извлекал свойства сотрудника из коллекции. Это помогает обновлять другие свойства без редактирования идентификатора сотрудника.

Ann 19.07.2024 10:17

Я также предоставил вам обновленный код, который вы можете протестировать. Убедитесь, что вы правильно заменили их в своем проекте.

Md Farid Uddin Kiron 19.07.2024 10:18

Если вы хотите сделать что-то подобное, заставьте его выбрать идентификатор из маршрута, а затем передать модель, это намного проще. У вас действительно должен быть DTO (объект передачи данных) для обеспечения безопасности, чтобы вы не взаимодействовали напрямую с сущностями или людьми, которые потенциально могут играть. Но, игнорируя часть DTO, это должно сработать для вас. [HttpPost("{id:int}", Name = nameof(EditEmployee))] public async Task<IActionResult> EditEmployee([FromRoute] int id, [FromBody] Сотрудник сотрудникМодель)

Netferret 19.07.2024 10:32
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В обоих случаях метод 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, не стесняйтесь менять свойство на своем контроллере.

Рад помочь вам в этом.

Md Farid Uddin Kiron 19.07.2024 11:09

Другие вопросы по теме