问题描述
我想使用 AJAX 将数据发布到我的 API,但我遇到了问题.我正在使用 Fiddler 测试我的 API,并且能够正确发布 JSON,但是在发布名称/值 urlencoded 字符串时,我收到一个 400 Bad Request,响应正文为 '{"":["The input was not valid."]}'.
I would like to post data to my API using AJAX but I'm having issues. I'm using Fiddler to test my API and I'm able to post JSON correctly but when posting a name/value urlencoded string I get a 400 Bad Request with the response body being '{"":["The input was not valid."]}'.
我的调试窗口显示:Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor:Information: Executing ObjectResult, writing value of type 'Microsoft.AspNetCore.Mvc.SerializableError'.
正在发布的 JSON 是:
The JSON being posted is:
{
"Name": "Test"
}
正在发布的表单数据是:
The form data being posted is:
Name=Test
这是控制器和动作:
[Route("api/[Controller]")]
[ApiController]
public class AccountsController : Controller
{
[HttpPost]
public IActionResult CreateAccount(Account account)
{
//code
}
}
这是 Account 类:
This is the Account class:
public class Account
{
public string Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string Website { get; set; }
}
在模型绑定期间似乎很明显存在问题,但表单数据似乎有效(我也使用 AJAX 生成了表单数据并获得了 400).
It seems obvious that there is an issue during model binding but the form data seems valid (I've also generated form data using AJAX and get a 400 as well).
推荐答案
在他的帖子 模型在 ASP.NET Core 中绑定 JSON POST 从 2016 年开始,Andrew Lock 解释说,为了在 ASP.NET Core 中绑定 JSON POST,[FromBody]
必须在参数上指定属性,如下所示:
In his post Model binding JSON POSTs in ASP.NET Core from 2016, Andrew Lock explains that in order to bind a JSON POST in ASP.NET Core, the [FromBody]
attribute must be specified on the argument, like so:
[HttpPost]
public IActionResult CreateAccount([FromBody] Account account)
{
// ...
}
随着 ASP.NET Core 2.1 引入 [ApiController]
,这不再是必需的.这里重要的是,当绑定的类型是复杂"(在您的示例中)时,此属性有效地推断出 [FromBody]
属性的存在.换句话说,就好像你已经编写了我上面演示的代码.
With the ASP.NET Core 2.1 introduction of [ApiController]
, this is no longer required. Of importance here is that this attribute effectively infers the presence of the [FromBody]
attribute when the type being bound is "complex" (which it is in your example). In other words, it's as though you have written the code as I demonstrated above.
Andrew 在他的帖子中还指出:
In his post, Andrew also states the following:
在某些情况下,您可能需要能够将两种类型的数据绑定到一个操作.在这种情况下,您会有点卡住,因为不可能让同一个端点接收两组不同的数据.
In some cases you may need to be able to bind both types of data to an action. In that case, you're a little bit stuck, as it won't be possible to have the same end point receive two different sets of data.
这里,当提到两种类型的数据时,Andrew 指的是 JSON 帖子和基于表单的 POST.他继续解释如何实际达到所需的结果.为您的目的修改他的示例,您需要执行以下操作:
Here, when referring to both types of data, Andrew is referring to both a JSON post and a form-based POST. He continues on to explain how to actually achieve the required result. Modifying his example for your purposes, you'd need to do something like the following:
// Form.
[HttpPost("FromForm")]
public IActionResult CreateAccountFromForm([FromForm] Account account)) =>
DoSomething(account);
// JSON.
[HttpPost("FromBody")]
public IActionResult CreateAccountFromBody(Account account) =>
DoSomething(account);
private IActionResult DoSomething(Account account) {
// ...
}
在 Andrew 的示例中,[FromBody]
是显式的,而 [FromForm]
是隐式的,但考虑到 [ApiController]
的影响具有默认值,上面的修改示例将其翻转.
In Andrew's example, the [FromBody]
is explicit and the [FromForm]
is implicit, but given the affect that [ApiController]
has on the defaults, the modified example above flips that around.
请参阅我的答案此处,了解允许将相同 URL 用于两个 FromForm 的潜在方法
和 FromBody
使用自定义 IActionConstraint
.
See my answer here for a potential approach that allows for the same URL to be used for both FromForm
and FromBody
using a custom IActionConstraint
.
这篇关于将表单数据发布到 MVC Core API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!