Получите значение null в контроллере при реализации IEnumerable в модели ASP NET

Я хочу использовать foreach для списка на С# в контроллере Create([FromBody] CardList card). Я получаю сообщение об ошибке. Тип «WordStudy.Models.CardList» можно использовать в операторах «foreach», только если он реализует «IEnumerable» или «IEnumerable» или если у него есть подходящий метод «GetEnumerator», тип возвращаемого значения которого имеет «Текущий». свойство и метод MoveNext. Когда я реализовал IEnumerable в своем классе, он становится нулевым.

скрипт.js

var currentCardNumber = 1;

function addCard() {

    currentCardNumber++;
    let newCardHTML = `
                    <div class = "header d-flex justify-content-between p-3">
                        <h4 class = "card-counter">${currentCardNumber}</h4>
                    </div>
                    <div class = "card-body row">
                        <div class = "term col">
                            <h3>Term</h3>
                            <input class = "form-control w-100" name = "term" >
                        </div>
                        <div class = "definition col">
                            <h3>Definition </h3>
                            <input class = "form-control w-100" name = "definition" >
                        </div>
                    </div>
            </div> `;
    let newCard = document.createElement('div');
    newCard.classList.add('card');
    newCard.classList.add('mt-3');
    newCard.innerHTML = newCardHTML;

    let addNewCard = document.querySelector('.cards');
    let referenceNode = document.getElementById('create-cards');
    addNewCard.insertBefore(newCard, referenceNode);

}
function saveCardDataToServer() {
    let cards = [];
    document.querySelectorAll('.cards > .card   ').forEach((card) => {

        let termInput = card.querySelector('input[name = "term"]');
        let definitionInput = card.querySelector('input[name = "definition"]');

        if (termInput && definitionInput) {
            let term = termInput.value.trim();
            let definition = definitionInput.value.trim();
            cards.push({
                Term: term,
                Definition: definition
            });
        }
        else {
            console.error("Input elements not found in card:", card);
        }
    })

    fetch('/Cards/Create/', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({Cards: cards})
    })
        .then(response => response.json())
        .then((data => {
            if (data.success) {
                console.info("Data successfully saved: ", data);
                window.location.href = "/Cards/Learning";
            } else {
                console.error("Error saving card: ", data.message);
            }
        }))
}
document.addEventListener('DOMContentLoaded', function() {
  let newCard = document.querySelector('.new-card');
  newCard.addEventListener('click', function() {
    addCard();
  });
  document.querySelector('form.cards').addEventListener('submit', function() {
    saveCardDataToServer();
  });
});

Вид

@model CardList

<!DOCTYPE html>
<html lang = "en">

<head>
    <script src = "~/js/script.js">
    </script>
    <link href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel = "stylesheet"
          integrity = "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin = "anonymous" asp-append-version = "true">    
</head>

<body>

<main class = "main">
  <div class = "container">
        <div class = "new-module d-flex justify-content-between mt-5">
            <h1>Create new module</h1>
            <a class = "btn btn-primary" asp-controller = "Cards" asp-action = "learning" type = "submit">Создать</a>
        </div>

        <div class = "card mt-5 p-2 pb-3">
            <h3>Title</h3>
            <input class = "form-control w-100" placeholder = "Enter a name">
        </div>
        <form asp-controller = "Cards" asp-action = "Create" method = "post" class = "cards">
            <div class = "card mt-6" id = "card">
                <div class = "header d-flex justify-content-between p-3">
                    <h4 class = "card-counter">1</h4>
                </div>
                <div class = "card-body row">
                    <div class = "term col">
                        <h3>Term</h3>
                        <input class = "form-control w-100" name = "term" >
                    </div>
                    <div class = "definition col">
                        <h3>Definition </h3>
                        <input class = "form-control w-100" name = "definition"  >
                    </div>
                </div>
            </div>

            <input type = "submit" value = "Create" id = "create-cards" class = "btn btn-primary mt-2"/>
        </form>
        <button class = "new-card w-100 d-flex justify-content-center align-items-center mt-4 mt-s rounded-2" style = "height: 5rem"  type = "button">
            <h3>+ Add card</h3>
        </button>
  </div>

</main>
</body>

</html>

Модели

public class Card
{
    public int CardId { get; set; }
    [Required]
    public string Term { get; set; } = string.Empty;
    public string Definition { get; set; } = string.Empty;
}

public class CardList : IEnumerable<Card>
{
    public List<Card> Cards { get; set; }

    public CardList()
    {
        Cards = new List<Card>();
    }
    
    public IEnumerator<Card> GetEnumerator()
    {
        return Cards.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Контроллер

public class CardsController : Controller
{
    public IActionResult Learning()
    {
        var cards = CardsRepository.GetCards();
        return View(cards);
    }

    public IActionResult Create()
    {
        return View();
    }
    [HttpPost]
    [Route("Cards/Create/")]
    public IActionResult Create([FromBody] CardList cards)
    
    {
        if (cards != null)
        {
            foreach (var card in cards)
            {
                if (!string.IsNullOrWhiteSpace(card.Term) && !string.IsNullOrWhiteSpace(card.Definition))
                {
                    CardsRepository.AddCard(card);
                }

            }

            return Json(new { success = true, message = "Card saved successfully " });
        }

        var errors = ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage);
        return Json(new { success = false, message = "Validation error", errors = errors });
    }
}

Если IEnumerable не реализован в контроллере CardList, Create([FromBody] CardList cards) получит правильные данные.

Ваша проблема связана не с Enumerator, а с привязкой модели IEnumerable. Существует множество примеров привязки IEnumerable к контроллеру различными способами. В моем тесте выборка не будет работать, как и ваша проблема, но вы можете попробовать другие способы, например цикл for, который в моем тесте будет работать так, как ожидалось. Однако наиболее рекомендуемый способ — использовать как можно более простую модель, поскольку сложный тип модели будет иметь множество ограничений. Learn.microsoft.com/en-us/aspnet/core/mvc/models/…

Fengzhi Zhou 01.07.2024 11:58
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Предлагаю вообще не продлевать IEnumerable. Идите проще.

public class Card
{
    public int CardId { get; set; }
    [Required]
    public string Term { get; set; } = string.Empty;
    public string Definition { get; set; } = string.Empty;
}

public class Deck
{
    public List<Card> Cards { get; set; }

    public Deck()
    {
        Cards = new List<Card>();
    }
}

Это дает вам простой json для работы:

{
  "Cards": [
    {
      "CardId": 1,
      "Term": "Term 1",
      "Definition": "Definition 1"
    },
    {
      "CardId": 2,
      "Term": "Term 2",
      "Definition": "Definition 2"
    },
    {
      "CardId": 3,
      "Term": "Term 3",
      "Definition": "Definition 3"
    }
  ]
}

Лучше всего сделать ваши DTO (объекты передачи данных) максимально простыми.

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