API 控制器无法从 POST body 读取 Json

API Controller unable to read Json from POST body

背景

我在 body 中将 JSON 发送到我的 API 控制器,但不断收到以下错误。

{"":["Unexpected character encountered while parsing value: {. Path '', line 1, position 1."]}

我的 HTTP 请求

HttpClient client = new HttpClient();
HttpRequest httpRequest;
HttpResponseMessage httpResponse = null;
httpRequest = new HttpRequest("", HostnameTb.Text, null);

var values = new Dictionary<string, string>
{
    { "APIKey", APIKeyTb.Text }
};

string json = JsonConvert.SerializeObject(values);
StringContent content = new StringContent(json.ToString(), Encoding.UTF8, "application/json");
httpResponse = client.PostAsync(HostnameTb.Text, content).Result;

var responseString = await httpResponse.Content.ReadAsStringAsync();

我的控制器是这样的。

[HttpPost]
public void Post([FromBody] string value)
{
  //Never gets here.
}

中的Jsonbody.

{"APIKey":"1283f0f8..."}

问题

我更愿意使用 .Net Core [From Body] 功能,而不是手动获取内容。

我希望 JSON 字符串在字符串 Value 参数中可用。

我错过了什么?

ASP.NET Core 尝试将 {"APIKey":"1283f0f8..."} 从 JSON 反序列化为 string 值,但失败了,因为它期望输入是有效的 JSON 字符串。

换句话说,如果您的 body 是 "{\"APIKey\":\"1283f0f8...\"}",您将在输入变量中获得预期的 JSON 字符串。

为了在不更改 HTTP 请求的情况下获取 APIKey 值,创建一个输入类型:

public class Input
{
    public string ApiKey { get; set; }
}

并将其用作控制器操作的输入:

[HttpPost]
public void Post([FromBody] Input input)
{
    var apiKey = input.ApiKey;
    // etc
}

或者,更改您的 HTTP 请求以发送 string:

// ...
var content = new StringContent(JsonConvert.SerializeObject(json), Encoding.UTF8, "application/json");
// ...

注意使用JsonConvert.SerializeObject()而不是ToString()"foo".ToString() 仍然只是 "foo",而你想要 "\"foo\""

这不是它的工作原理。 [FromBody] 调用序列化程序来反序列化请求正文。然后,模型绑定器尝试将其绑定到参数。在这里,它不能这样做,因为您要绑定到一个字符串,而请求正文是一个字典。本质上,幕后发生的事情(伪代码)是:

value = JsonConvert.DeserializeObject<string>(dictionaryAsJson);

您收到来自 JSON.NET 的反序列化错误,因为它无法将 JSON 解析为字符串。

如果您希望将值作为字符串,那么您应该 post 类似于 text/plain 而不是 application/json。否则,您需要绑定到一个实际代表 JSON 对象的类型,这里是 Dictionary<string, string>

我在使用 ASP.NET Core 3.1 时遇到了同样的问题。我正在 POST 将 JSON 连接到我的 API 控制器,看起来像:

public JsonResult Save([FromBody]MainDetails obj){ ... }

我的问题是 MainDetails 对象的 属性 ChildDetails.StartDateDateTime 类型,而我发送的是 null JSON 中的值。这导致反序列化在控制器上失败。我将 属性 类型从 DateTime 更改为 DateTime? 以使其工作。

基本上,需要检查并确保您 POST 的 JSON 对于您反序列化的目标对象有效。如果您有不可为 null 的属性,并且在 JSON 中发送的值为 null,那么您的反序列化将失败(不告诉您原因)。 希望这有帮助。