400 错误请求通过 HttpClient.PutAsync 提交 Json 到 WebApi
400 Bad Request submitting Json to WebApi via HttpClient.PutAsync
通常,从服务到 webapi 调用都会使用序列化对象,但在这种情况下,我 对调用使用 json 表示。
该过程是将 json 反序列化为正确的 class,然后照常处理。
HttpClient 放[=27=]
方法是从控制台应用程序中调用的
public async Task<ApiMessage<string>> PutAsync(Uri baseEndpoint, string relativePath, Dictionary<string, string> headerInfo, string json)
{
HttpClient httpClient = new HttpClient();
if (headerInfo != null)
{
foreach (KeyValuePair<string, string> _header in headerInfo)
_httpClient.DefaultRequestHeaders.Add(_header.Key, _header.Value);
}
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json-patch+json"));
var content = new StringContent(json, Encoding.UTF8, "application/json-patch+json");
var response = await httpClient.PutAsync(CreateRequestUri(relativePath, baseEndpoint), content);
var data = await response.Content.ReadAsStringAsync();
...
}
端点
呼叫永远不会到达端点。如果我删除 [FromBody]
标记,则会命中端点,但正如预期的那样,该参数为空。似乎发生了某种过滤。
[HttpPut()]
[Route("")]
[SwaggerResponse(StatusCodes.Status200OK)]
[SwaggerResponse(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> UpdatePaymentSync([FromBody] string paymentSyncJson)
{
if (string.IsNullOrEmpty(paymentSyncJson))
return BadRequest();
//hack: don't have access to models so need to send json rep
var paymentSync = JsonConvert.DeserializeObject<PaymentSync>(paymentSyncJson);
....
}
这是 json 负载。我以为 [FromBody]
处理简单类型,但这证明我错了。
{
"paymentSyncJson": {
"id": 10002,
"fileName": "Empty_20190101.csv",
"comments": "Empty File",
"processingDate": "2019-01-02T19:43:11.373",
"status": "E",
"createdDate": "2019-01-02T19:43:11.373",
"createdBy": "DAME",
"modifiedDate": null,
"modifiedBy": null,
"paymentSyncDetails": []
}
}
您的有效负载不是字符串,它是 json,这就是为什么运行时无法将正文解析为您请求的 string paymentSyncJson
。
要解决它,请创建一个匹配的 dto 来反映 json
public class PaymentDto
{
public PaymentSyncDto PaymentSyncJson { get; set; }
}
public class PaymentSyncDto
{
public int Id { get; set; }
public string FileName { get; set; }
public string Comments { get; set; }
public DateTime ProcessingDate { get; set; }
public string Status { get; set; }
public DateTime CreatedDate { get; set; }
public string CreatedBy { get; set; }
public DateTime ModifiedDate { get; set; }
public string ModifiedBy { get; set; }
public int[] PaymentSyncDetails { get; set; }
}
然后在controller方法中使用它从请求体中读取数据
public async Task<IActionResult> UpdatePaymentSync([FromBody] PaymentDto payment)
只是扩展我的评论。
OP 做了:
[HttpPut()]
[Route("")]
[SwaggerResponse(StatusCodes.Status200OK)]
[SwaggerResponse(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> UpdatePaymentSync([FromBody] string paymentSyncJson)
{
if (string.IsNullOrEmpty(paymentSyncJson))
return BadRequest();
//hack: don't have access to models so need to send json rep
var paymentSync = JsonConvert.DeserializeObject<PaymentSync>(paymentSyncJson);
....
}
在他们放置 [FromBody] string paymentSyncJson
的地方,FromBody 将尝试反序列化为您指定的类型,在本例中为 string
。我建议这样做:
public async Task<IActionResult> UpdatePaymentSync([FromBody] JObject paymentSyncJson)
然后你可以改变这一行:
var paymentSync = JsonConvert.DeserializeObject<PaymentSync>(paymentSyncJson);
收件人:
var paymentSync = paymentSyncJson.ToObject<PaymentSync>();
通常,从服务到 webapi 调用都会使用序列化对象,但在这种情况下,我 对调用使用 json 表示。
该过程是将 json 反序列化为正确的 class,然后照常处理。
HttpClient 放[=27=]
方法是从控制台应用程序中调用的
public async Task<ApiMessage<string>> PutAsync(Uri baseEndpoint, string relativePath, Dictionary<string, string> headerInfo, string json)
{
HttpClient httpClient = new HttpClient();
if (headerInfo != null)
{
foreach (KeyValuePair<string, string> _header in headerInfo)
_httpClient.DefaultRequestHeaders.Add(_header.Key, _header.Value);
}
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json-patch+json"));
var content = new StringContent(json, Encoding.UTF8, "application/json-patch+json");
var response = await httpClient.PutAsync(CreateRequestUri(relativePath, baseEndpoint), content);
var data = await response.Content.ReadAsStringAsync();
...
}
端点
呼叫永远不会到达端点。如果我删除 [FromBody]
标记,则会命中端点,但正如预期的那样,该参数为空。似乎发生了某种过滤。
[HttpPut()]
[Route("")]
[SwaggerResponse(StatusCodes.Status200OK)]
[SwaggerResponse(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> UpdatePaymentSync([FromBody] string paymentSyncJson)
{
if (string.IsNullOrEmpty(paymentSyncJson))
return BadRequest();
//hack: don't have access to models so need to send json rep
var paymentSync = JsonConvert.DeserializeObject<PaymentSync>(paymentSyncJson);
....
}
这是 json 负载。我以为 [FromBody]
处理简单类型,但这证明我错了。
{
"paymentSyncJson": {
"id": 10002,
"fileName": "Empty_20190101.csv",
"comments": "Empty File",
"processingDate": "2019-01-02T19:43:11.373",
"status": "E",
"createdDate": "2019-01-02T19:43:11.373",
"createdBy": "DAME",
"modifiedDate": null,
"modifiedBy": null,
"paymentSyncDetails": []
}
}
您的有效负载不是字符串,它是 json,这就是为什么运行时无法将正文解析为您请求的 string paymentSyncJson
。
要解决它,请创建一个匹配的 dto 来反映 json
public class PaymentDto
{
public PaymentSyncDto PaymentSyncJson { get; set; }
}
public class PaymentSyncDto
{
public int Id { get; set; }
public string FileName { get; set; }
public string Comments { get; set; }
public DateTime ProcessingDate { get; set; }
public string Status { get; set; }
public DateTime CreatedDate { get; set; }
public string CreatedBy { get; set; }
public DateTime ModifiedDate { get; set; }
public string ModifiedBy { get; set; }
public int[] PaymentSyncDetails { get; set; }
}
然后在controller方法中使用它从请求体中读取数据
public async Task<IActionResult> UpdatePaymentSync([FromBody] PaymentDto payment)
只是扩展我的评论。
OP 做了:
[HttpPut()]
[Route("")]
[SwaggerResponse(StatusCodes.Status200OK)]
[SwaggerResponse(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> UpdatePaymentSync([FromBody] string paymentSyncJson)
{
if (string.IsNullOrEmpty(paymentSyncJson))
return BadRequest();
//hack: don't have access to models so need to send json rep
var paymentSync = JsonConvert.DeserializeObject<PaymentSync>(paymentSyncJson);
....
}
在他们放置 [FromBody] string paymentSyncJson
的地方,FromBody 将尝试反序列化为您指定的类型,在本例中为 string
。我建议这样做:
public async Task<IActionResult> UpdatePaymentSync([FromBody] JObject paymentSyncJson)
然后你可以改变这一行:
var paymentSync = JsonConvert.DeserializeObject<PaymentSync>(paymentSyncJson);
收件人:
var paymentSync = paymentSyncJson.ToObject<PaymentSync>();