模型绑定的复杂类型不能为抽象或值类型,并且必须具有无参数构造函数

时间:2019-01-17 13:33:05

标签: c# asp.net asp.net-core .net-core

我遇到以下问题,我创建了一个应用程序,将游戏类别和游戏本身添加到数据库中。我创建了一个关系,但是不幸的是,当我添加到数据库中时,我得到了一个错误。

  

模型绑定的复杂类型不能是抽象或值类型,并且必须   有一个无参数的构造函数。

游戏类别模型

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

我不知道怎么了。

我的错误屏幕

enter image description here

5 个答案:

答案 0 :(得分:1)

  

无法创建Relationship.ViewModels.AddGameViewModel的实例。模型绑定的复杂类型不能为抽象或值类型,并且必须具有无参数的构造函数。

让我们尝试解决此错误。

  

无法创建Relationship.ViewModels.AddGameViewModel的实例。

不言自明:模型绑定组件正在尝试创建您的类型的实例,但是失败了。

  

模型绑定的复杂类型

“模型绑定”是指它们被ASP.NET管道绑定。 “复杂类型”基本上是不是stringint这样的“基本”类型的任何类型。您的模型类是复杂的类型。

  

一定不是抽象的

模型绑定系统将希望能够创建类的实例,因此它不能是抽象的;它必须是具体的。您显示的所有类型都是具体的,所以这不是问题。

  

或值类型

您不能将struct类型用于模型绑定;这只是其局限性之一。幸运的是,您的类型都是所有类,因此可以忽略它。

  

,并且必须具有无参数的构造函数。

ASP.NET不知道如何向模型构造函数提供参数。它只能做new T()的等效项,因此所有模型类型都必须定义一个参数为零的构造函数。这就是您看到错误的原因;您的AddGameViewModel类仅定义此构造函数:

public AddGameViewModel(IEnumerable<GameCategory> categories)

C#语言的功能之一是,当您不手动指定构造函数时,它将为您添加一个默认的构造函数。在代码中定义构造函数时,不会添加此默认构造函数。

在所有其他模型中,您没有定义任何构造函数,因此编译器会为您添加默认的构造函数。对于AddGameViewModel,您已经添加了一个构造函数,因此,要解决该问题,您还必须添加默认的构造函数:

public AddGameViewModel()
{
}

答案 1 :(得分:1)

您需要将[FromBody]添加到参数,以便asp.net核心知道如何绑定模型。

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

答案 2 :(得分:0)

在撰写本文时,我在Asp.NET Core 2.2控制器中遇到了此问题,在该控制器中,将类型注入了一种方法。将类型移动到Controller的构造函数可以解决该问题。由于这实际上是不可接受的,因此我们最终将有问题的类从Controller重构到了已经广泛使用单例的处理层中。此时再添加一个即可解决我们的问题。

请注意,这是Asp.Net Core内置的OOB IoC容器。其他IoC提供程序可能能够更好地处理方法的注入属性。

Lamar可能是替代方法。

使用模型联编程序可能也可行,因为联编程序可能更干净地使用单例和/或支持构造函数注入。

答案 3 :(得分:0)

就我而言,我天真地绑定了一个复杂的对象(没有no-args构造函数的复杂对象):

Edit.cshtml.cs:

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

单击“保存”时出现此运行时错误:

System.InvalidOperationException:无法创建类型为“ MyNamespace.MyComplexClass”的实例。

模型绑定的复杂类型不能是抽象或值类型,并且必须具有无参数构造函数。

或者,将“ WorkflowItem”属性设置为 “ MyNamespace.EditModel”构造函数中的非null值。在 Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.CreateModel(ModelBindingContext bindingContext)在 Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.BindModelCoreAsync(ModelBindingContext bindingContext,Int32 propertyData)

我需要对象(它有要显示给用户的信息),但我 不需要“更新” (至少不需要此编辑菜单)。

解决方案:

只需删除[BindProperty]即可消除该错误。

答案 4 :(得分:0)

我有同样的错误。构造函数是内部的 ,我以 public 的形式返回它,并且模型正常通过了。