Сложные типы, связанные с моделью, не должны быть абстрактными или значениями и должны иметь конструктор без параметров
У меня есть следующая проблема, я создал приложение для добавления категорий игр и самих игр в базу данных. Я создал отношения и, к сожалению, когда я добавляю в базу данных, я получаю сообщение об ошибке.
Сложные типы, связанные с моделью, не должны быть абстрактными или значениями и должны иметь конструктор без параметров.
Модель игровой категории
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]
устранил ошибку.