在Web API .NET Core中接受x-www-form-urlencoded数据

54

我有一个.NET Core Web API,在尝试将包含一些json数据的数据发布到API时,返回了415 Unsupported Media Error。以下是在Chrome调试器中返回的部分内容:

Request URL:http://localhost:51608/api/trackAllInOne/set
Request Method:POST
Status Code:415 Unsupported Media Type
Accept:text/javascript, text/html, application/xml, text/xml, */*
Content-Type:application/x-www-form-urlencoded

action:finish
currentSco:CSharp-SSLA:__How_It_Works_SCO
data:{"status":"incomplete","score":""}
activityId:13
studentId:1
timestamp:1519864867900

我认为这与我的控制器不接受 application/x-www-form-urlencoded 数据有关 - 但我不确定。 我已经尝试使用 Consumes 装饰我的控制器,但似乎没有起作用。

[HttpPost]
[Route("api/trackAllInOne/set")]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult Post([FromBody] PlayerPackage playerPackage)
{ etc..}

非常感激任何帮助。

以下代码在 .NET 4.6.1 中运行良好,我能够捕获并处理上面显示的帖子。

[ResponseType(typeof(PlayerPackage))]
public async Task<IHttpActionResult> PostLearningRecord(PlayerPackage playerPackage)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var id = Convert.ToInt32(playerPackage.ActivityId);
    var learningRecord = await _context.LearningRecords.FindAsync(id);
    if (learningRecord == null)
        return NotFound();
etc...

什么是 PlayerPackage?你是如何从前端发送请求的? - Edward
PlayerPackage是在线课程跟踪学生在该课程中进度的信息。我无法控制系统如何进行发布。我的WebApi的工作是捕获这些发布并将它们保存在我的跟踪系统中。 - Roddy Balkan
你想接受带有 data:{"status":"incomplete","score":""} 的数据还是记录所有的主体 action:finish currentSco:CSharp-SSLA:__How_It_Works_SCO data:{"status":"incomplete","score":""} activityId:13 studentId:1 timestamp:1519864867900 - Edward
是的,我确实想接受JSON数据; {"status: "incomplete"等... 这是关键部分,也是导致它无法工作的原因。当我删除JSON时,它似乎可以正常工作- 但JSON是我最需要的。 - Roddy Balkan
以下代码在 .net 4.6.1 中对于相同的帖子曾经正常工作: `[ResponseType(typeof(PlayerPackage))] public async Task<IHttpActionResult> PostLearningRecord(PlayerPackage playerPackage) { if (!ModelState.IsValid) { return BadRequest(ModelState); } var id = Convert.ToInt32(playerPackage.ActivityId); var learningRecord = await _context.LearningRecords.FindAsync(id); if (learningRecord == null) return NotFound();` - Roddy Balkan
5个回答

84

请尝试使用[FromForm]代替[FromBody]

public IActionResult Post([FromForm] PlayerPackage playerPackage)
  • FromBody > 从 JSON 绑定

  • FromForm > 从表单参数绑定

您也可以完全移除 [FromBody],并试一试。因为您期望表单编码应该告诉它绑定到对象。


好的,你可以尝试的另一件事是将其完全删除(不是理想的解决方案,但它有效)。 - Aeseir
4
有什么办法可以同时支持application/x-www-urlencoded和application/json吗?我正在创建两个具有相同路由名称的函数,并共享一个私有函数来实现这一点,但我想知道是否有更简单的方法来支持JSON和FORM绑定。 - Robin1990
Robin,使用两个方法签名会起作用吗?一个带有[Consumes]属性用于URL表单,另一个带有application/json?然后一个具有[FromFrom],另一个具有[FromBody]。一旦绑定完成,让一个方法直接调用另一个方法。只是一个想法,没有测试过。我认为如果您删除[From ...]属性,它会自动解决,但也许他们需要[consumes]属性来帮助? - MarkD
太棒了! [FromForm] 那也是我的错。 - Peyman Majidi

55

对于PlayerPackage,请求应该发送一个PlayerPackage Json对象。根据您的描述,您无法控制从其他地方发布的请求。

对于该请求,其类型为application/x-www-form-urlencoded,它将以字符串格式发送带有{"status":"incomplete","score":""}数据,而不是Json对象。如果你想接受{"status":"incomplete","score":""},我建议你像下面这样改变方法,然后通过Newtonsoft.Json将字符串转换为对象。

[HttpPost]
[Route("~/api/trackAllInOne/set")]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult Post([FromForm] string data)
{
    PlayerPackage playerPackage = JsonConvert.DeserializeObject<PlayerPackage>(data);
    return Json(data);
}

1
我已经按照这个做了,但是当我从Postman发送时,“data”为空。你有什么想法为什么会这样? - r3plica
@r3plica,我会使用自定义类型而不是字符串。将数据放入类型本身中,然后在[FromForm]旁边,放置[FromForm] CustomType请求,然后在该自定义类型中访问数据属性(或其他作为表单编码请求一部分的属性)。这就是我所做的,在我的情况下,它有效。 - firecape
1
@firecape 我遇到了完全相同的问题,数据为空且先前的值为字符串。 - DanielV

33

这对我来说起了奇效:

[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult Post([FromForm]IFormCollection value)

3
IFormCollection 是关键。谢谢。 - Pierre

2
可以设置成这样
[HttpPost()]/[HttpGet()]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult>  MethodName([FromForm] IFormCollection value)

别忘了加上[FromForm]


0

我曾经遇到过同样的问题。FormDataCollection没有默认构造函数,而这是Formatters所必需的。请改用IFormCollection。


1
请使用[FromForm]属性代替[FromBody]。 - jahansha
公开的IActionResult搜索([FromForm] IFormCollection类型) { 返回 Ok(); } - jahansha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接