.NET Core中HttpPost接口多个[FromBody]参数绑定报错该如何解决?
Action has more than one parameter that was specified or inferred as bound from request body. Only one parameter per action may be bound from body
该报错的核心原因是ASP.NET Core中请求体默认是仅可读取一次的缓冲流,因此系统限制单个接口Action只能绑定一个标记了[FromBody]的参数,你当前代码给两个参数都加了[FromBody]特性,就触发了该约束。
方案1:封装统一请求DTO(最推荐)
将两个需要从请求体读取的参数封装到同一个自定义请求类中,接口仅绑定一个[FromBody]参数即可。
步骤1:定义统一接收类
// 自定义请求DTO,按需添加字段即可 public class CreateUserRequest { public UserBO UserBO { get; set; } public SiteCode SiteCode { get; set; } }
步骤2:修改接口代码
[HttpPost] public async Task<IActionResult> Create([FromBody] CreateUserRequest request) { try { await _userService.CreateUserAsync(request.UserBO, request.SiteCode); return Created(nameof(Get), request.UserBO); } catch (Exception ex) { return HandleException(ex); } }
该方案符合接口设计规范,可扩展性强,后期要新增请求参数只需修改DTO类即可。
方案2:调整其中一个参数的绑定源
如果其中一个参数是短内容的标识类参数(比如站点ID、租户ID、操作标识等),可以将其调整为从Query、路由、Header等其他位置绑定,不需要走请求体。
示例(将SiteCode调整为从Query参数读取):
[HttpPost] public async Task<IActionResult> Create([FromBody] UserBO userBO, [FromQuery] SiteCode siteCode) { try { await _userService.CreateUserAsync(userBO, siteCode); return Created(nameof(Get), userBO); } catch (Exception ex) { return HandleException(ex); } }
前端请求时将siteCode拼接在请求URL后即可,例:POST /api/xxx?siteCode=xxx,请求体仅传输userBO的JSON内容。如果要走路由绑定,只需给接口加路由模板[HttpPost("{siteCode}")],参数标记[FromRoute]即可。
方案3:直接接收JObject自行反序列化(不推荐)
如果不想新增DTO类,可以直接用JObject接收完整请求体,再手动反序列化为两个对象,该方案缺少编译时类型校验,容易出现运行时错误,仅建议临时调试使用:
[HttpPost] public async Task<IActionResult> Create([FromBody] JObject requestBody) { try { var userBO = requestBody["userBO"].ToObject<UserBO>(); var siteCode = requestBody["siteCode"].ToObject<SiteCode>(); await _userService.CreateUserAsync(userBO, siteCode); return Created(nameof(Get), userBO); } catch (Exception ex) { return HandleException(ex); } }
内容的提问来源于stack exchange,提问作者hanushi

