Model bound complex types must not be abstract or value types and must have a parameterless constructor

I have the following problem, I created an application to add game categories and the games themselves to the database. I created a relationship and unfortunately when I add to the database I get an error.

Model bound complex types must not be abstract or value types and must
have a parameterless constructor.

Game Category Model

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; }
    }
}

Game Model

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();
        }
    }
}

and last is 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);
        }
    }
}

I don’t have any idea what is wrong.

My error screen

enter image description here

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

Could not create an instance of relationship.ViewModels.AddGameViewModel. Model bound complex types must not be abstract or value types and must have a parameterless constructor.

Let’s try and break this error down.

Could not create an instance of relationship.ViewModels.AddGameViewModel.

Pretty self-explanatory: the model-binding components are trying to create an instance of your type, but failed.

Model bound complex types

“Model bound” refers to that they’re being bound by the ASP.NET pipeline. “complex types” are basically any types which aren’t “basic” like string or int. Your model classes are complex types.

must not be abstract

The model-binding system is going to want to be able to create instances of the class, so it cannot be abstract; it must be concrete. All of the types you’ve show are concrete so this isn’t the problem.

or value types

You can’t use struct types with model-binding; it’s just one of its limitations. Fortunately your types are all classes, so you can ignore this.

and must have a parameterless constructor.

ASP.NET doesn’t know how to supply parameters to model constructors. It can only do the equivalent of new T(), so all your model types must define a constructor which has zero parameters. This is the reason you’re seeing the error; your AddGameViewModel class only defines this constructor:

public AddGameViewModel(IEnumerable<GameCategory> categories)

One of the C# language features is that when you don’t specify a constructor manually, it adds a default one for you. When you define a constructor in your code, this default constructor is not added.

In all of your other models, you aren’t defining any constructors so the compiler is adding the default one for you. In the case of AddGameViewModel you have added a constructor, so to fix the problem you must also add the default constructor:

public AddGameViewModel()
{
}

Solution 2

you need add [FromBody] to the parameter so that asp.net core know how to bind the model.

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

Solution 3

As of this writing, I experienced this issue in an Asp.NET Core 2.2 Controller where the type was injected on one of the methods. Moving the type to the Controller’s constructor worked around it. Since this wasn’t really acceptable we eventually refactored the offending class out of the Controller and into the processing layer where singletons are already used extensively. Adding one more at that point cleared up our problem.

Note this is the OOB IoC container that is built-in to Asp.Net Core. Other IoC providers may be better able to handle injecting properties on methods.

Lamar might be an alternative.

Using a model binder might also have worked since the binder could probably use the singleton and/or support constructor injection more cleanly.

Solution 4

In my case, I was naively binding a complex object (a complex object without a no-args constructor):

Edit.cshtml.cs:

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

I got this runtime error when I clicked "Save":

System.InvalidOperationException: Could not create an instance of type ‘MyNamespace.MyComplexClass’.

Model bound complex types must not be abstract or value types and must have a parameterless constructor.

Alternatively, set the ‘WorkflowItem’ property to a
non-null value in the ‘MyNamespace.EditModel’ constructor. at
Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.CreateModel(ModelBindingContext
bindingContext) at
Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.BindModelCoreAsync(ModelBindingContext
bindingContext, Int32 propertyData)

I needed the object (it had information I wanted to display to the user), but I didn’t need to "update" it (at least not in this edit menu).

SOLUTION:

Simply removing [BindProperty] eliminated the error.

Solution 5

I had this same error. Constructor was internal, I returned it back as public, and the model was passed normally.

Solution 6

Adding [ApiController] at the top of my Controller’s class fixed it for me:

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

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply