You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 18:57:21