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

Paw*_*elC 1 c# asp.net .net-core asp.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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

游戏模型

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

视图模型

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

游戏库

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后是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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我不知道怎么了。

我的错误画面

在此处输入图片说明

Pau*_*ner 28

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

让我们试着打破这个错误。

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

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

模型绑定复杂类型

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

不能抽象

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

或值类型

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

并且必须有一个无参数的构造函数。

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

public AddGameViewModel(IEnumerable<GameCategory> categories)
Run Code Online (Sandbox Code Playgroud)

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

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

public AddGameViewModel()
{
}
Run Code Online (Sandbox Code Playgroud)

  • 我只是添加了一个空的构造函数,因为我记得你甚至可以定义几个:D 确实,错误没有显示出来,但它没有保存,这里是表单字段没有名称的问题放。非常感谢您的帮助 :) (2认同)
  • ASP.NET 绑定器确实知道如何向模型构造函数提供参数。如果此功能以前在 net Framework 中有效,但在 net core 中不再有效,请添加 [FromBody] 属性。 (2认同)

Lan*_*ang 5

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

[HttpPost]
public IActionResult Add([FromBody] AddGameViewModel addGameViewModel)
Run Code Online (Sandbox Code Playgroud)

  • 我可以确认,只需添加 [FromBody] 即可解决我的问题。 (2认同)
  • `[FromBody]` 在某些情况下修复它的原因是因为 api 配置为 `SuppressInferBindingSourcesForParameters`。请检查[此 MSDN 链接](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.apibehavioroptions.suppressinferbindingsourcesforparameters?view=aspnetcore-5.0)。 (2认同)
  • 小心[FormBody] vs [FromBody] 哈哈 (2认同)