无法在 POST 调用中从 Route 和 Body 接收值
Not able to receive values from Route and Body in a POST call
在一个 Asp.Net 核心 5.0 项目上,我有 ApiController
路线和模型:
[HttpPost("users/{userId:int}/confirm-email")]
public async Task<IActionResult> ConfirmEmail(Model model) { }
public class Model {
[FromRoute] public Int32? UserId { get; set; }
[FromQuery] public String Token { get; set; }
}
结果:我得到了我期望的...
UserId = 10
Token = "ABC"
我尝试在正文中而不是在查询参数中接收令牌:
public class Model {
[FromRoute] public Int32? UserId { get; set; }
[FromBody] public String Token { get; set; }
}
在这种情况下,我得到了错误:
"errors": {
"$": [
"The JSON value could not be converted to System.String. Path: $ | LineNumber: 0 | BytePositionInLine: 1."
]
}
我用 Insomnia.Rest 调用了 API 正文是:
{
"token": "ABC"
}
然后我尝试将 [FromBody]
添加到控制器操作:
[HttpPost("users/{userId:int}/confirm-email")]
public async Task<IActionResult> ConfirmEmail([FromBody]Model model) { }
public class Model {
[FromRoute] public Int32? UserId { get; set; }
[FromBody] public String Token { get; set; }
}
结果:我从 body 获得了令牌,但现在 userId 为空。
UserId = null
Token = "ABC"
我一直在尝试一些变体,但我无法弄清楚发生了什么。
我也试过从Angular调用API,结果是一样的。
知道我错过了什么吗?
默认情况下,模型绑定在 HTTP 请求中从以下来源获取键值对形式的数据:
- 表单字段
- 请求正文(对于具有 [ApiController] 属性的控制器。)
- 路由数据
- 查询字符串参数
- 上传的文件
对于每个目标参数或 属性,将按照前面列表中指示的顺序扫描源。
您可以参考以下截图:
我们可以看到,应用于属性 的[FromRoute]
和[FromForm]
属性不起作用。它使用默认的推理规则来绑定模型。
然后,当 [FromBody]
属性应用于复杂类型参数时(将 [FromBody]
属性添加到控制器操作),将忽略应用于其属性的任何绑定源属性。因此,UserId
为空。更多详细信息,请参阅 [FromBody]
attribute and Binding source parameter inference。
因此,在这种情况下,要从路由和请求体中访问值,最简单的方法是在 ConfirmEmail
方法中添加一个参数,代码如下:
[HttpPost("users/{userId:int}/confirm-email")]
public async Task<IActionResult> ConfirmEmail(Model model, [FromRoute]int userid)
{
//set the userid
model.userId = userid;
return Ok("success");
}
结果如下:
此外,您也可以尝试创建自定义模型绑定器来绑定模型。
这里有一些相关的文章,你可以参考一下:
在一个 Asp.Net 核心 5.0 项目上,我有 ApiController
路线和模型:
[HttpPost("users/{userId:int}/confirm-email")]
public async Task<IActionResult> ConfirmEmail(Model model) { }
public class Model {
[FromRoute] public Int32? UserId { get; set; }
[FromQuery] public String Token { get; set; }
}
结果:我得到了我期望的...
UserId = 10
Token = "ABC"
我尝试在正文中而不是在查询参数中接收令牌:
public class Model {
[FromRoute] public Int32? UserId { get; set; }
[FromBody] public String Token { get; set; }
}
在这种情况下,我得到了错误:
"errors": {
"$": [
"The JSON value could not be converted to System.String. Path: $ | LineNumber: 0 | BytePositionInLine: 1."
]
}
我用 Insomnia.Rest 调用了 API 正文是:
{
"token": "ABC"
}
然后我尝试将 [FromBody]
添加到控制器操作:
[HttpPost("users/{userId:int}/confirm-email")]
public async Task<IActionResult> ConfirmEmail([FromBody]Model model) { }
public class Model {
[FromRoute] public Int32? UserId { get; set; }
[FromBody] public String Token { get; set; }
}
结果:我从 body 获得了令牌,但现在 userId 为空。
UserId = null
Token = "ABC"
我一直在尝试一些变体,但我无法弄清楚发生了什么。
我也试过从Angular调用API,结果是一样的。
知道我错过了什么吗?
默认情况下,模型绑定在 HTTP 请求中从以下来源获取键值对形式的数据:
- 表单字段
- 请求正文(对于具有 [ApiController] 属性的控制器。)
- 路由数据
- 查询字符串参数
- 上传的文件
对于每个目标参数或 属性,将按照前面列表中指示的顺序扫描源。
您可以参考以下截图:
我们可以看到,应用于属性 的[FromRoute]
和[FromForm]
属性不起作用。它使用默认的推理规则来绑定模型。
然后,当 [FromBody]
属性应用于复杂类型参数时(将 [FromBody]
属性添加到控制器操作),将忽略应用于其属性的任何绑定源属性。因此,UserId
为空。更多详细信息,请参阅 [FromBody]
attribute and Binding source parameter inference。
因此,在这种情况下,要从路由和请求体中访问值,最简单的方法是在 ConfirmEmail
方法中添加一个参数,代码如下:
[HttpPost("users/{userId:int}/confirm-email")]
public async Task<IActionResult> ConfirmEmail(Model model, [FromRoute]int userid)
{
//set the userid
model.userId = userid;
return Ok("success");
}
结果如下:
此外,您也可以尝试创建自定义模型绑定器来绑定模型。
这里有一些相关的文章,你可以参考一下: