25

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

1
  • 2
    The message is clear: AddGameViewModel doesn't have a parameterless constructor (it requires a IEnumerable<GameCategory> categories parameter). If you're new to Model Binding in ASP.NET Core, the docs should be helpful. Commented Jan 17, 2019 at 13:35

7 Answers 7

42

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()
{
}
7
  • 2
    I just added an empty constructor, because I remember that you can define even a few: D It is true that the error did not show up, but it did not save, and here was the problem that the form fields did not have the name set. Thank you very much for your help :)
    – PawelC
    Commented Jan 17, 2019 at 13:53
  • 1
    @KirkLarkin Right you are. The same problems apply to both, but I can see it's MVC from the stack. I'll fix this answer. Commented Jan 17, 2019 at 13:59
  • 2
    ASP.NET binder does know how to supply parameters to model constructors. Where this previously worked in net framework and no longer works in net core, add the [FromBody] attribute.
    – CRice
    Commented Apr 28, 2020 at 2:13
  • 1
    Awesome extremely detailed answer! Thank you sir. Clear understanding.
    – Bigbear
    Commented May 13, 2021 at 16:47
  • 1
    Thanks @CRice your comment solved my problem! - Thanks for the answer Paul Turner.
    – Joel Brown
    Commented Feb 17 at 13:43
18

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)
3
  • 2
    I can confirm that simply adding [FromBody] fixed my issue with this. Commented Apr 30, 2019 at 17:40
  • 2
    The reason [FromBody] fixes it in some situations is because the api is configured to SuppressInferBindingSourcesForParameters. Please check this MSDN link. Commented May 13, 2021 at 15:09
  • 2
    Beware of [FormBody] vs [FromBody] lol
    – edencorbin
    Commented Oct 27, 2021 at 13:38
2

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

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

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.

1

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.

1
  • I think the better approach to this is not remove the Attribute, but instead not pass the model, since it's already getting passed, and instead add whatever it is you need to the model, and then use the model.property...
    – NovaDev
    Commented Oct 26, 2021 at 14:35
1

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

0

If you're hitting this error message and are using the built-in dependency injection from ASP.NET Core MVC, make sure you add the FromServices attribute here:

enter image description here

I forgot to add it and then was getting this same message:

enter image description here

An unhandled exception occurred while processing the request. InvalidOperationException: Could not create an instance of type 'Company.Service.IFacilityImporter'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Record types must have a single primary constructor. Alternatively, give the 'facilityImporter' parameter a non-null default value. Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexObjectModelBinder.CreateModel(ModelBindingContext bindingContext)

Not the answer you're looking for? Browse other questions tagged or ask your own question.