Reputation: 2119
Normally, serialized objects would be used from the services to the webapi calls but in this instance I have to use a json representation for the call.
The process would be to deserialize the json to the proper class, then process as usual.
Method is called from within a console app
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();
...
}
The call never hits the endpoint. The endpoint is hit if I remove the [FromBody]
tag but as expected, the parameter is null. There seems to be some sort of filtering happening.
[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);
....
}
This is the json payload. I thought [FromBody]
took care of simple types but this is proving me wrong.
{
"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": []
}
}
Upvotes: 0
Views: 1220
Reputation: 14417
Just expanding on my Comment.
The OP did:
[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);
....
}
Where they have put [FromBody] string paymentSyncJson
, FromBody will try and deserialise into the type you specify, in this case string
. I suggest doing:
public async Task<IActionResult> UpdatePaymentSync([FromBody] JObject paymentSyncJson)
Then you can change this line:
var paymentSync = JsonConvert.DeserializeObject<PaymentSync>(paymentSyncJson);
To:
var paymentSync = paymentSyncJson.ToObject<PaymentSync>();
Upvotes: 1
Reputation: 16856
Your payload is not a string, it's a json, that's why the runtime can't parse the body to your requested string paymentSyncJson
.
To solve it, create a matching dto which reflects the 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; }
}
Then use it in the controller method to read the data from the request body
public async Task<IActionResult> UpdatePaymentSync([FromBody] PaymentDto payment)
Upvotes: 1