When trying to an object in an Action in a Controller it sporadically seems to be null. I discovered that it is due to the ReadAsStringAsync()
in the SendAsync()
override of the DelegatingHandler
. The issue is with the content. When my client sends a content body and it is read in the logger it is never read by the Controller Action Invoker (or may be somewhere in the JsonFormatter
). I suspect the subsequent call to Content.ReadAsStringAsync()
doesnt throw an exception but also doesnt not return the expected content body (some info is returned stating that the async read is completed).
But my problem remains since I want to read a [FromBody]
parameter in an action and it is null when the RaceCondition of Content.ReadStringAsync
is won by the DelegatingHandler
. When JsonFormatter
wins it though, I get the object but that is rare (only at service startup).
Here is my DelegatingHandler
code:
public class LogHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var apiRequest = new WebApiUsageRequest(request);
WriteLog(apiRequest);
request.Content.ReadAsStringAsync().ContinueWith(t =>
{
apiRequest.Content = t.Result;
WriteLog(apiRequest);
});
return base.SendAsync(request, cancellationToken).ContinueWith(task =>
{
var apiResponse = new WebApiUsageResponse(task.Result);
apiResponse.Content = task.Result.Content != null ? task.Result.Content.ReadAsStringAsync().Result : null;
WriteLog(apiResponse);
return task.Result;
});
}
}
Does anyone have a clue to the solution of this issue?
ReadAsStreamAsync method returns the body content.
This worked for me:
Returned for me the json representation of my parameter object, so I could use it for exception handling and logging.
Found as accepted answer here
Here's what I ended up doing:
@pirimoglu's answer of using a "using" block didn't work for me, since when the reader was disposed, the underlying stream was also closed.
This is by design. In ASP.NET Web API the body content is treated a forward-only stream that can only be read once.
You might try utilising ASP.NET Web API Tracing but I haven't test it with POST request yet so I'm not sure how/if it is tracing the request body (it is tracing parameters for GET request for sure). You can read more here:
but if you use the code below in the SendAsync it works properly
. . .