Ошибка проверки формы ASP.NET Core 6.0: «Поле fieldNameHere является обязательным». хотя такого поля не существует

Я создаю веб-приложение ASP.NET Core 6.0.

Моя проверка формы не работает, и когда я вывожу ошибки ModelState, я вижу это:

Ключ: адрес электронной почты, ошибка: поле «адрес электронной почты» является обязательным.
Ключ: Пароль, Ошибка: Поле Пароль обязательно.

Эти ошибки не отображаются ни в одной из форм на моей странице.

Во время написания этого поста я не менял код, но по какой-то причине

Ключ: Пароль, Ошибка: Поле Пароль является обязательным.

больше не появляется, что меня еще больше смущает.

В моем представлении редактирования есть все необходимые поля, и что бы я ни пытался, я не могу избавиться от ошибок.

Чтобы упростить визуализацию, моя страница выглядит так:

EditPageView

Ниже приведен весь соответствующий код:

@model Replay.ViewModels.ApplicationUserRoleViewModel

@{
    ViewData["Title"] = "Edit User";
}

<h1>Edit User</h1>

<form asp-controller = "Account" asp-action = "Edit" method = "post">
    <div asp-validation-summary = "ModelOnly" class = "text-danger"></div>
    <div class = "form-group">
        <label asp-for = "ApplicationUser.Email" class = "control-label"></label>
        <input asp-for = "ApplicationUser.Email" class = "form-control" />
        <span asp-validation-for = "ApplicationUser.Email" class = "text-danger"></span>
    </div>
    <div class = "form-group">
        <label asp-for = "ApplicationUser.FullName" class = "control-label"></label>
        <input asp-for = "ApplicationUser.FullName" class = "form-control" />
        <span asp-validation-for = "ApplicationUser.FullName" class = "text-danger"></span>
    </div>
    <div class = "form-group">
        <label asp-for = "ApplicationUser.Password" class = "control-label"></label>
        <input asp-for = "ApplicationUser.Password" class = "form-control" />
        <span asp-validation-for = "ApplicationUser.Password" class = "text-danger"></span>
    </div>
    <div class = "form-group">
        <label asp-for = "ApplicationUser.Active" class = "control-label"></label>
        <input asp-for = "ApplicationUser.Active" type = "checkbox" class = "form-check-input" />
        <span asp-validation-for = "ApplicationUser.Active" class = "text-danger"></span>
    </div>

    <div class = "form-group">
        <table>
            @for (int i = 0; i < Model.Roles.Count; i++)
            {
                <tr>
                    <td>
                        @Html.HiddenFor(m => m.Roles[i].Id)
                        @Html.HiddenFor(m => m.Roles[i].Name)
                        @Html.DisplayFor(m => m.Roles[i].Name)
                    </td>
                    <td>@Html.CheckBoxFor(m => m.Roles[i].Selected)</td>
                </tr>
            }
        </table>
    </div>

    <button type = "submit" class = "btn btn-primary">Save</button>
</form>

Код С#:

using Replay.Models;

namespace Replay.ViewModels
{
    public class ApplicationUserRoleViewModel
    {
        public ApplicationUser ApplicationUser { get; set; }
        public List<RoleViewModel> Roles { get; set; }

        public ApplicationUserRoleViewModel()
        {
        }

        public ApplicationUserRoleViewModel(ApplicationUser applicationUser, List<Role> roles, List<int> userRoleIds)
        {
            ApplicationUser = applicationUser;

            Roles = roles.Select(r => new RoleViewModel
            {
                Id = r.Id,
                Name = r.Name,
                Selected = userRoleIds.Contains(r.Id)
            }).ToList();
        }
    }

    public class RoleViewModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public bool Selected { get; set; }
    }
}
using System.ComponentModel.DataAnnotations;

namespace Replay.Models;

public class ApplicationUser
{
    [Key]
    public int Id { get; set; }
    public string Email { get; set; }
    public string FullName { get; set; }
    public string Password { get; set; }
    public Boolean Active { get; set; }
}
using System.ComponentModel.DataAnnotations;

namespace Replay.Models
{
    public class Role
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
    }
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(ApplicationUserRoleViewModel viewModel)
{
    if (!ModelState.IsValid)
    {
        foreach (var key in ModelState.Keys)
        {
            var state = ModelState[key];

            foreach (var error in state.Errors)
            {
                System.Diagnostics.Debug.WriteLine($"Key: {key}, Error: {error.ErrorMessage}");
            }

            var roles = _dbContext.Role.ToList();

            var userRoleIds = _dbContext.UserRoles
                                        .Where(ur => ur.UserId == viewModel.ApplicationUser.Id)
                                        .Select(ur => ur.RoleId).ToList();

            viewModel.Roles = roles.Select(r => new RoleViewModel
            {
                Id = r.Id,
                Name = r.Name,
                Selected = userRoleIds.Contains(r.Id)
            }).ToList();

            return View(viewModel);
        }
    }

    var user = _dbContext.ApplicationUser.Find(viewModel.ApplicationUser.Id);

    if (user == null)
    {
        return NotFound();
    }

    user.Email = viewModel.ApplicationUser.Email;
    user.FullName = viewModel.ApplicationUser.FullName;
    user.Password = viewModel.ApplicationUser.Password;
    user.Active = viewModel.ApplicationUser.Active;

    var userRoles = _dbContext.UserRoles.Where(ur => ur.UserId == user.Id).ToList();
    _dbContext.UserRoles.RemoveRange(userRoles);

    var selectedRoleIds = viewModel.Roles
                                   .Where(r => r.Selected)
                                   .Select(r => r.Id).ToList();

    foreach (var roleId in selectedRoleIds)
    {
        _dbContext.UserRoles.Add(new UserRole { UserId = user.Id, RoleId = roleId });
    }

    _dbContext.SaveChanges();

    return RedirectToAction("Index");
}
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Replay.Models
{
    public class UserRole
    {
        [Key]
        public int Id { get; set; }
        [ForeignKey("ApplicationUser")]
        public int UserId { get; set; }
        [ForeignKey("Role")]
        public int RoleId { get; set; }
    }
}

Что я пробовал:

  • удалил все группы форм (а именно ApplicationUser.Email и ApplicationUser.Password) и все равно получил ошибки. Может быть, интересно узнать, что при удалении ApplicationUser.Email и ApplicationUser.Password из моего поля зрения конкретно говорилось, что теперь отсутствуют ApplicationUser.Email, ApplicationUser.Password, Emailand Password.
  • Добавление @Html.HiddenFor(), которое, очевидно, даже не скомпилируется, поскольку в моей модели представления нет ни Email, ни Password.
  • Я также попробовал добавить ? к Email и Password в своем классе ApplicationUser.

Чего я ожидал:

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

Когда в заголовке вы говорите «Поле ATTRIBUTE является обязательным», вы имеете в виду «Поле SomeFieldName является обязательным»? Атрибут работы что-то значит в .NET-стране.

Flydog57 27.05.2024 02:43

Да, я это имел в виду, спасибо за замечание, исправлю.

DeUlo 27.05.2024 02:47

Проблема в том, что вы используете класс сущности EF в качестве ViewModel. Не делай этого. Определите отдельный класс для представления опубликованных данных формы.

Dai 27.05.2024 07:46

Я не совсем уверен, что изменить. Насколько я понимаю, мой ApplicationUserRoleViewModel не является классом сущности EF? Не могли бы вы привести мне пример того, что должно отличаться/как вы видите, что мой ApplicationUserRoleViewModel является классом сущности EF? Из определения я знаю, что это будет означать, что моя ViewModel напрямую сопоставляется с таблицей в моей базе данных, а это не так. Спасибо за помощь :)

DeUlo 27.05.2024 11:27

Здравствуйте, удалось ли вам добиться какого-либо прогресса? У вас все еще та же проблема? @Dai сказал: используйте пользовательскую модель представления, которая определяет все свойства, которые вы используете в своем представлении, а затем, как только вы отправите форму, в вашем методе публикации вы можете получить значение из viewModel и передать их в свою модель домена. Означает, что не используйте модель домена непосредственно в вашей модели представления.

Md Farid Uddin Kiron 27.05.2024 11:28

У меня все еще была проблема, я думаю, что понимаю, что вы двое имеете в виду, и реализовал ее. Теперь он правильно сохраняется! Большое спасибо! Я опубликую ответ с обновленным кодом через секунду.

DeUlo 27.05.2024 12:19
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
112
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Благодаря @Dai и @Md-Farid-Uddin-Kiron я нашел ответ. Мне пришлось изменить свою ViewModel, чтобы она не включала напрямую EF-модель. Мой ApplicationUserRoleViewModel изменился на это, и тогда это сработало:

using System.ComponentModel.DataAnnotations;
using Replay.Models;

namespace Replay.ViewModels
{
    public class ApplicationUserRoleViewModel
    {
        public int Id { get; set; }
        [Required]
        public string Email { get; set; }
        [Required]
        public string FullName { get; set; }
        [Required]
        public string Password { get; set; }
        public bool Active { get; set; }
        public List<RoleViewModel> Roles { get; set; }
    }

    public class RoleViewModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public bool Selected { get; set; }
    }
}

В качестве улучшения измените public List<RoleViewModel> Roles { get; set; } на public List<RoleViewModel> Roles { get; } = new List<RoleViewModel>();, чтобы свойство не было потенциально null. Модуль связывания моделей ASP.NET отлично работает со свойствами списка, состоящими только из get.

Dai 27.05.2024 17:59

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