如何修复ASP.NET Core Web API子对象创建失败问题?
ASP.NET Core Web API(.NET7)Post请求对象创建失败问题解决
问题概述
在.NET7的ASP.NET Core Web API项目中,BooksController的CreateAsync Post方法无法正常创建Book对象,Swagger返回400验证错误,且不想使用DTO解决该问题。
实体类代码
public class Book { public int Id { get; set; } public string Title { get; set; } public string Author { get; set; } public int Count { get; set; } // Navigation property public BookDetail BookDetail { get; set; } } public class BookDetail { public int Id { get; set; } public string Description { get; set; } // Foreign key public int BookId { get; set; } // navigation properties public Book Book { get; set; } }
控制器相关代码
[HttpPost("Create")] public async Task<ActionResult<Book>> CreateAsync(Book book) { if (book == null) { return BadRequest(); } _db.Books.Add(book); await _db.SaveChangesAsync(); return CreatedAtRoute(nameof(GetByIdAsync), new { id = book.Id }, book); } [HttpGet("{id:int}")] public async Task<ActionResult<Book>> GetByIdAsync(int id) { var book = await _db.Books.FindAsync(id); if (book == null) { return NotFound(); } return Ok(book); }
Swagger返回的错误信息
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-2695d8ae6781a68ca32420345ecf40a1-9851e26a3bcb27f2-00", "errors": { "book": [ "The book field is required." ], "$.bookDetail.book": [ "The JSON value could not be converted to BookShopApp.Models.Book. Path: $.bookDetail.book | LineNumber: 9 | BytePositionInLine: 20." ] } }
测试用的JSON输入
变体1
{ "id": 0, "title": "string", "author": "string", "count": 0, "bookDetail": { "id": 0, "description": "string", "bookId": 0, "book": "string" } }
变体2
{ "title": "Book Title", "author": "Author Name", "count": 3, "bookDetail": { "description": "Book Description" } }
已尝试的配置(未解决问题)
// in Program.cs builder.Services .AddControllers() .AddJsonOptions(x => x.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles);
解决方案
1. 修改实体类的可空导航属性
由于.NET7默认启用Nullable参考类型,BookDetail中的Book导航属性被标记为不可空,导致模型绑定验证失败。将其改为可空类型:
public class BookDetail { public int Id { get; set; } public string Description { get; set; } public int BookId { get; set; } // 将导航属性改为可空 public Book? Book { get; set; } }
2. 明确控制器参数的绑定来源
在CreateAsync方法的参数上添加[FromBody]特性,确保模型绑定从请求体获取JSON数据:
[HttpPost("Create")] public async Task<ActionResult<Book>> CreateAsync([FromBody] Book book) { // 原有逻辑不变 }
3. 调整JSON输入格式
创建对象时无需传递BookDetail中的Book(导航属性)和BookId(外键由EF Core自动关联生成),使用以下正确的JSON格式:
{ "title": "Book Title", "author": "Author Name", "count": 3, "bookDetail": { "description": "Book Description" } }
4. 配置EF Core的实体关系(可选)
在DbContext的OnModelCreating方法中明确配置一对一关系,确保EF Core正确处理外键关联:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<BookDetail>() .HasOne(bd => bd.Book) .WithOne(b => b.BookDetail) .HasForeignKey<BookDetail>(bd => bd.BookId); }
完成以上步骤后,重新运行项目,即可正常通过Post请求创建Book对象。
内容的提问来源于stack exchange,提问作者DevMis
相关产品推荐
相关产品推荐

