0

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.

HttpClient Put

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();

        ... 
    }

Endpoint

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": []
    }
  }
4
  • if it's not hitting your endpoint it could be the route, I see you have a Route attribute on your method that is empty, do you have a route prefix on your controller class? Commented Feb 6, 2019 at 17:35
  • 2
    [FromBody] will attempt to deserialise to the given object - in your case a string.. you could put ([FromBody] JObject payment) - this will prevent the need for your deserialiseobject. to convert to object you can do payment.ToObject<>() Commented Feb 6, 2019 at 17:44
  • @CallumLinington make that an answer please so I can "check it" - that did it!!! Commented Feb 6, 2019 at 18:35
  • @WillLopez done! Commented Feb 6, 2019 at 22:27

2 Answers 2

1

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>();
Sign up to request clarification or add additional context in comments.

Comments

1

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)

1 Comment

Thank you for the response but there was an answer in the comments above. Typically this is how I do it and works great...in this instance it's an interop issue between systems

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.