I'd like to see what the request body of my HTTP request contained for debugging purposes. Here's what I've got right now:
var httpResponseMessage = await _httpClient.PostAsync(uri, objectToInsert, jsonFormatter);
//This throws an exception
var thisDoesntWork = await httpResponseMessage.RequestMessage.Content.ReadAsStringAsync();
This throws an ObjectDisposedException. How can I view the request body to make sure the JSON being sent is correct?
The short answer is you can't after the request has already been sent. HttpClient disposes the content body after the request is made as a convenience to the developer. See Why do HttpClient.PostAsync and PutAsync dispose the content? for some detail.
As an alternative, you could inherit from an existing HttpContent implementation, override the Dispose method, and log the body of the content prior to disposal.
Or, as suggested, use an external tool to monitor the request in flight.
You'd need to first create a HttpRequestMessage to pass to the HttpClient. Then you can just evaluate/log the content.
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content=JsonSerializer.Serialize(objectToInsert);
Console.WriteLine(request.Content.ReadAsStringAsync().Result);
HttpResponseMessage response = await httpClient.SendAsync(request);
ObjectDisposedException is thrown because you're disposing the HttpRequestMessage and HttpClient before Content.ReadAsStringAsync() finishes.
Note that Content.ReadAsStringAsync() is an asynchronous method. You need to wait for it to complete before disposing the HttpClient.
If you are not wanting to use async you can add .Result to force the code to execute synchronously:
var response = httpClient.PostAsync(BaseUri, new FormUrlEncodedContent(parameters)).Result;
var contents = response.Content.ReadAsStringAsync().Result;
Related
I have an middleware which executes based on specific routing and redirects the request to call another service and the response of the service call need to be sent back to the caller.
public Task Invoke(HttpContext context)
{
return GetServiceDataAsync(context);
}
private async Task<object> GetServiceDataAsync(HttpContext context)
{
var response = service.GetDataAsync();
return await response;
}
When executing this call, I do see the service call returns response properly. But, the response is not written back as HttpResponseMessage so the caller can read again from the body.
In this case, the response was already read and converted to response. Need some pointers on how to provide the same response back to the caller. With this code, I'm seeing 200 status code, but the body is empty. TIA !
I'm trying to use a service bus Azure function, where I accept a BrokeredMessage, then perform http requests, and then afterward decide whether to complete, abandon, or dead letter the message. But I've been finding the BrokeredMessage is being disposed early if I await an http request. It's throwing System.ObjectDisposedException: 'BrokeredMessage has been disposed.' if I try to use it at all.
Example:
public static async void Run(BrokeredMessage message, TraceWriter log)
{
var httpClient = new HttpClient()
{
BaseAddress = new Uri("http://google.com")
};
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var request = new HttpRequestMessage(HttpMethod.Get, "/");
HttpResponseMessage response = await httpClient.SendAsync(request);
message.DeadLetter(); //Throws exception
}
I'm not sure if I'm doing something wrong or missing something but I can't figure out how to make any actions I need to do with the message after the await work correctly.
You shouldn't call Complete() explicitly. Azure Functions runtime will complete the message if the function finishes successfully or abandon if the function fails.
The Functions runtime receives a message in PeekLock mode and calls Complete on the message if the function finishes successfully, or calls Abandon if the function fails.
from docs
The issue was the function needs to return Task instead of void for the async to work correctly. After making that change it awaits correctly.
So, in the following snippet, why is ReadAsStringAsync an async method?
var response = await _client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
Originally I expected SendAsync to send the request and load the response stream into memory at which point reading that stream would be in-process CPU work (and not really async).
Going down the source code rabbit hole, I arrived at this:
int count = await _stream.ReadAsync(destination, cancellationToken).ConfigureAwait(false);
https://github.com/dotnet/corefx/blob/0aa654834405dcec4aaa9bd416b2b31ab8d3503e/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnection.cs#L967
This makes me think that maybe the connection is open until the response stream is actually read from some source outside of the process? I fully expect that I am missing some fundamentals regarding how streams from Http Connections work.
SendAsync() waits for the request to finish and the response to start arriving.
It doesn't buffer the entire response; this allows you to stream large responses without ever holding the entire response in memory.
When I try the following code:
var request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Timeout = 3; // a small value
var response = request.GetResponse();
Console.WriteLine(response.ContentLength);
for a URL that I know it is going to take more than 3 millisecond to load (I put a Thread.Sleep(110000) in Application_BeginRequest) it works fine and throws a WebException as expected.
Problem is when I switch to async method:
var response = request.GetResponseAsync().Result;
or
var response = await request.GetResponseAsync();
This async version completely ignores any Timeout value, including ReadWriteTimeout and ServicePoint.MaxIdleTime
I couldn't find anything about Timeout in MSDN's GetResponseAsync() now I'm wondering if it is a bug in GetResponseAsync() or something is wrong in the way I use async here?
Timeout does not apply to asynchronous HttpWebRequest requests. To quote the docs:
The Timeout property has no effect on asynchronous requests
I recommend you use HttpClient instead, which was designed with asynchronous requests in mind.
Follow a solution to solve the problem.
await Task.Run(() => {
var varHttpResponse = varWebRequest.GetResponse();
});
Is there a way to use restsharp synchronously? Every method I see in Visual Studio has the "async" postfix and the restsharp main page, (which has the following example):
// execute the request
RestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
Clearly makes the distinction between sync and async requests:
// easy async support
client.ExecuteAsync(request, response => {
Console.WriteLine(response.Content);
});
How can I access this "Execute" sync method?
I asked in their googlegroups and they said that it is because of "platorm limitations" when using wp7. Pretty neat right?