运行.NET应用触发System.InvalidOperationException请求体参数绑定异常
运行时抛出的异常信息如下:
System.InvalidOperationException: 'Action 'ProjectAPI.Controllers.UserController.CreatePasswordHash (TravelMoreAPI)' 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. Inspect the following parameters, and use 'FromQueryAttribute' to specify bound from query,
'FromRouteAttribute' to specify bound from route, and 'FromBodyAttribute' for parameters to be bound from body:
Byte[]& passwordHash
Byte[]& passwordSalt'
核心问题是你将控制器内部的密码哈希工具方法错误声明成了public级别的接口Action:
ASP.NET Core 框架启动时会自动扫描控制器中所有public类型的方法,将其识别为可响应HTTP请求的Action。对于没有显式标记参数绑定来源的Action参数,框架会默认推断绑定规则,尝试从请求体读取参数值。而你写的CreatePasswordHash方法包含password、passwordHash、passwordSalt三个参数,其中两个out byte[]参数也被框架判定为需要从请求体绑定,违反了框架“单个Action仅允许一个参数从请求体绑定”的强制规则,直接抛出异常。
本质上这个方法是做内部密码哈希计算的工具方法,根本不需要、也不应该直接对外接收HTTP请求。
- 优先方案:将
CreatePasswordHash的访问修饰符从public改为private,让框架不再将其识别为对外接口。这个方法只需要在控制器内部的注册、修改密码等业务接口中调用即可,调整后的代码如下:
// 改为私有方法,仅控制器内部调用,不会被识别为接口Action private void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt) { using (var hmac = new HMACSHA512()) { passwordSalt = hmac.Key; passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password)); } }
- 特殊场景方案:如果确实需要对外暴露生成密码哈希的HTTP接口(生产环境强烈不建议,会泄露核心密码处理逻辑),不要直接复用带out参数的内部方法当Action,需要单独定义规范的请求/返回数据结构,保证Action只有一个从请求体绑定的参数,内部再调用私有工具方法完成计算,示例代码如下:
// 请求参数DTO,唯一从请求体绑定的参数 public class GenHashRequest { public string Password { get; set; } } // 返回结果DTO public class GenHashResponse { public byte[] PasswordHash { get; set; } public byte[] PasswordSalt { get; set; } } // 合法的对外接口Action [HttpPost("gen-password-hash")] public ActionResult<GenHashResponse> GenerateHash([FromBody] GenHashRequest request) { if (string.IsNullOrWhiteSpace(request.Password)) return BadRequest("密码不能为空"); CreatePasswordHash(request.Password, out var hash, out var salt); return Ok(new GenHashResponse { PasswordHash = hash, PasswordSalt = salt }); }
内容的提问来源于stack exchange,提问作者user12240282

