Сложные типы, связанные с моделью, не должны быть абстрактными или значениями и должны иметь конструктор без параметров

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

Сложные типы, связанные с моделью, не должны быть абстрактными или значениями и должны иметь конструктор без параметров.

Модель игровой категории

using System.Collections.Generic;

namespace relationship.Models
{
    public class GameCategory
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public ICollection<Game> Game { get; set; }
    }
}

Модель игры

namespace relationship.Models
{
    public class Game
    {
        public int GameId { get; set; }
        public string Name { get; set; }

        public GameCategory Category { get; set; }
        public int CategoryId { get; set; }
    }
}

ViewModel

using relationship.Models;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace relationship.ViewModels
{
    public class AddGameViewModel
    {     
        [Required]
        public string GameName { get; set; }
        public int CategoryID { get; set; }

        public List<SelectListItem> Categories { get; set; }

        public AddGameViewModel(IEnumerable<GameCategory> categories)
        {
            Categories = new List<SelectListItem>();
            foreach (var catData in categories)
            {
                Categories.Add(new SelectListItem { Text = catData.Name.ToString(), Value = catData.Id.ToString() });
            }
            return;
        }
    }
}

GameRepository

using System.Collections.Generic;
using System.Linq;

namespace relationship.Models
{
    public class GameRepository : IGameRepository
    {
        private readonly AppDbContext appDbContext;
        public GameRepository(AppDbContext dbContext)
        {
            appDbContext = dbContext;
        }

        public void AddGame(Game game)
        {
            appDbContext.Games.Add(game);
            appDbContext.SaveChanges();
        }

        public IEnumerable<Game> Games()
        {
            return appDbContext.Games.ToList();
        }
    }
}

и, наконец, GameController

using Microsoft.AspNetCore.Mvc;
using relationship.Models;
using relationship.ViewModels;

namespace relationship.Controllers
{
    public class GameController : Controller
    {
        private readonly IGameRepository gameRepository;
        private readonly ICategoryRepository categoryRepository;

        public GameController(IGameRepository gameRepo, ICategoryRepository catRepo)
        {
            gameRepository = gameRepo;
            categoryRepository = catRepo;
        }

        public IActionResult Index()
        {
            return View();
        }

        [HttpGet]
        public IActionResult Add()
        {
            var addGameViewModel = new AddGameViewModel(categoryRepository.GameCategory());
            return View(addGameViewModel);
        }

        [HttpPost]
        public IActionResult Add(AddGameViewModel addGameViewModel)
        {
            if (ModelState.IsValid)
            {
                GameCategory gameCategory = categoryRepository.GetDetails(addGameViewModel.CategoryID);

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

                Game game = new Game
                {
                    Name = addGameViewModel.GameName,
                    Category = gameCategory
                };

                gameRepository.AddGame(game);
                return RedirectToAction("Index");
            }
            return View(addGameViewModel);
        }
    }
}

Я понятия не имею, что не так.

Мой экран ошибок

6 ответов

Решение

Не удалось создать экземпляр отношений.ViewModels.AddGameViewModel. Сложные типы, связанные с моделью, не должны быть абстрактными или значениями и должны иметь конструктор без параметров.

Давайте попробуем сломать эту ошибку.

Не удалось создать экземпляр отношений.ViewModels.AddGameViewModel.

Довольно понятно: компоненты привязки к модели пытаются создать экземпляр вашего типа, но не удалось.

Связанные с моделью сложные типы

"Привязка к модели" означает, что они связаны конвейером ASP.NET. "сложные типы" - это в основном любые типы, которые не являются "базовыми", как string или же int, Ваши модельные классы являются сложными типами.

не должно быть абстрактным

Система привязки к модели захочет иметь возможность создавать экземпляры класса, поэтому она не может быть абстрактной; это должно быть конкретным. Все типы, которые вы показываете, являются конкретными, так что это не проблема.

или типы значений

Вы не можете использовать struct типы с привязкой к модели; это только одно из его ограничений. К счастью, ваши типы все классы, так что вы можете игнорировать это.

и должен иметь конструктор без параметров.

ASP.NET не знает, как передавать параметры конструкторам моделей. Это может сделать только эквивалент new T()поэтому все типы вашей модели должны определять конструктор с нулевыми параметрами. Это причина, по которой вы видите ошибку; ваш AddGameViewModel класс определяет только этот конструктор:

public AddGameViewModel(IEnumerable<GameCategory> categories)

Одна из особенностей языка C# заключается в том, что когда вы не указываете конструктор вручную, он добавляет для вас конструктор по умолчанию. Когда вы определяете конструктор в своем коде, этот конструктор по умолчанию не добавляется.

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

public AddGameViewModel()
{
}

Вам нужно добавить [FromBody] к параметру, чтобы ядро ​​asp.net знало, как связать модель.

[HttpPost]
public IActionResult Add([FromBody] AddGameViewModel addGameViewModel)

Добавление [ApiController]в верхней части класса моего контроллера исправил это для меня:

      [Route("api/[controller]")]
[ApiController]
public class ProductController : Controller
{
    ...
}

На момент написания этой статьи я столкнулся с этой проблемой в контроллере Asp.NET Core 2.2, где тип был введен в один из методов. Перемещение типа в конструктор контроллера обошлось. Поскольку на самом деле это было неприемлемо, мы в конечном итоге реорганизовали проблемный класс из Контроллера на уровень обработки, где синглтоны уже широко используются. Добавление еще одного в этот момент решило нашу проблему.

Обратите внимание, что это контейнер OOB IoC, встроенный в Asp.Net Core. Другие провайдеры IoC могут лучше справляться с внедрением свойств в методы.

Ламар мог бы быть альтернативой.

Использование связывателя модели также могло сработать, поскольку связыватель, вероятно, мог бы более чисто использовать одноэлементную инъекцию и / или поддержку конструктора.

У меня была такая же ошибка. Конструктор был внутренним, я вернул его как публичный, и модель прошла нормально.

В моем случае я наивно привязывал сложный объект (сложный объект без конструктора без аргументов):

Edit.cshtml.cs:

namespace MyNamespace.Pages.CSDA
{
    public class EditModel : PageModel
    {
        ...
        [BindProperty]
        public MyComplexClass WorkflowItem { get; set; }
        ...

Я получил эту ошибку времени выполнения, когда нажал "Сохранить":

System.InvalidOperationException: не удалось создать экземпляр типа MyNamespace.MyComplexClass.

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

В качестве альтернативы установите для свойства WorkflowItem ненулевое значение в конструкторе MyNamespace.EditModel. в Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.CreateModel(ModelBindingContext bindingContext) в Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.BindModelCoreAsync(свойство ModelBindingContextbindingData), Int32

Мне был нужен объект (в нем была информация, которую я хотел показать пользователю), но мне не нужно было его "обновлять" (по крайней мере, не в этом меню редактирования).

РЕШЕНИЕ:

Просто удалите [BindProperty] устранил ошибку.

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