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

26,936

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

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

Solution 4

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 5

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.

Share:
26,936
PawelC
Author by

PawelC

Full Stack Web Developer in Leaware.com

Updated on January 12, 2022

Comments

  • PawelC
    PawelC over 2 years

    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