无法在 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");
    }

结果如下:

此外,您也可以尝试创建自定义模型绑定器来绑定模型。

这里有一些相关的文章,你可以参考一下:

Custom Model Binding in ASP.NET Core

Custom Model Binding In ASP.NET Core MVC