.NET 6迁移MVC API后HttpClient PostAsync调用返回400错误
.NET 6 MVC API POST请求返回400 Bad Request 排查方案
问题根因
这个问题是ASP.NET Core MVC [ApiController] 特性的默认机制导致的,属于模型校验提前返回:
- 标记
[ApiController]的控制器会在请求进入Action方法前自动执行模型状态校验,校验不通过时直接返回400响应,不会执行后续接口逻辑,这就是你API端点断点始终不命中的原因 - 返回的错误响应明确提示
Token字段为必填项,说明你的UserModel(或其继承的基类)中存在一个标记了[Required]特性的Token属性,而WPF端POST请求序列化后的JSON中未携带该字段的有效值 - Swagger调用正常是因为Swagger测试时你手动填写了Token字段的有效值;PUT请求正常是因为你发起UpdateUser请求时传入的UserModel实例已经携带了合法的Token值,而InsertUser时传入的实例该字段为空
- 之前Minimal API版本没有触发问题,是因为Minimal API默认不会自动执行数据注解模型校验,即使字段缺失也会正常进入业务逻辑。
修复方案
按以下优先级排查处理:
- 检查WPF端传参
断点查看InsertUser方法传入的user实例,确认Token属性是否为null、空字符串或未赋值,补传该字段的合法值即可。 - 修正模型定义
如果POST接口不需要接收Token字段:- 移除
Token属性上的[Required]校验特性 - 如果该字段仅用于其他场景(比如认证传递、PUT逻辑使用),给属性加上Newtonsoft.Json的
[JsonIgnore]特性,避免序列化/反序列化时校验该字段
- 移除
- 显式指定绑定源
给所有接口的复杂类型参数显式加上[FromBody]特性,明确告诉框架从请求体反序列化模型,避免隐式绑定源推断的意外行为:[HttpPost] public async Task<IActionResult> InsertUser([FromBody] UserModel model) { _appDbContext.Users.Add(model); var result = await _appDbContext.SaveChangesAsync(); return result > 0 ? Ok() : Problem("User was not inserted"); } [HttpPut] public async Task<IActionResult> UpdateUser([FromBody] UserModel model) { if(await _appDbContext.Users.FindAsync(model.Id) is UserModel efModel) { _mapper.Map(model, efModel); _appDbContext.Users.Update(efModel); var result = await _appDbContext.SaveChangesAsync(); return result > 0 ? Ok() : Problem("User was not updated"); } return Problem("User not found."); } - 关闭自动模型校验(不推荐)
如果你需要完全手动控制模型校验逻辑,可以在Program.cs中添加以下配置关闭自动400返回行为,之后可以在Action内部通过ModelState.IsValid自行判断校验结果:builder.Services.Configure<ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; });
附:相关代码与环境信息
基础MVC配置
builder.Services.AddControllers(); app.MapControllers();
WPF端请求实现
HttpClient通过DI容器注入到UserService类中,序列化扩展方法使用Newtonsoft.Json将对象转换为application/json格式的StringContent:
// POST请求(异常版本) public async Task<bool> InsertUser(UserModel user) { var result = await _httpClient.PostAsync("/api/Users", user.AsJsonContent()); return result.IsSuccessStatusCode; } // PUT请求(正常版本) public async Task<bool> UpdateUser(UserModel user) { var result = await _httpClient.PutAsync("/api/Users", user.AsJsonContent()); return result.IsSuccessStatusCode; } // JSON序列化扩展方法 public static StringContent AsJsonContent(this object obj) { string json = JsonConvert.SerializeObject(obj); var content = new StringContent(json, Encoding.UTF8, "application/json"); return content; }
错误响应原文
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-ac9fc01b742547b2525eef9de28ea6a0-d123c5b603ff637c-00", "errors": { "Token": [ "The Token field is required." ] } }
原Minimal API实现
//Registered in another class app.MapPost("/Users", InsertUser); public async Task<bool> InsertUser(UserModel model) { await _appDbContext.Users.AddAsync(model); var result = await _appDbContext.SaveChangesAsync(); return result > 0; }
内容的提问来源于stack exchange,提问作者Skint007
相关产品推荐
相关产品推荐

