The documentation about the PostAsync method of the HttpClient is a bit...on the low side.
I'm wondering about the behaviour of it:
Does it bring any exceptions in case of timeout or when the Website called throws an exception? If not what happens in These cases?
As example
using (HttpClient Client = new HttpClient())
{
var result = Client.PostAsync(url, content).Result;
}
The site called sometime throws exceptions or in the case of high traffic times out. I'm not sure what the result is then. Do I get exceptions, "endless Loop" (thus timeouts don't occur), or is just the result empty if exceptions are thrown or a timeout occurs?
As a first note, please avoid using Result. It is a blocking call. You should use the async/await keywords. Mark the corresponding method as async and prepend the method call with await:
var result = await Client.PostAsync(url, content);
Regarding your question, the result of this call is a Task<HttpResponseMessage>.
Statuses of a Tasks can be found here TaskStatus Enumeration. Of course this call can fail. So you should catch any exception that may be thrown.
Related
Picture the following code:
var client = new HttpClient();
var response = await client.GetAsync("www.someaddress.yo");
string content = await response.Content.ReadAsStringAsync();
Is there any added benefit, other than possibly saving a single thread, by writing the above code the following way:
var client = new HttpClient();
string content = await client.GetAsync("www.someaddress.yo")
.ContinueWith(r => r.Result.Content.ReadAsStringAsync()).Result;
Correct me if I'm wrong, but I believe performance-wise both codes end up doing the same amount of work.
The second snippet has no benefits, doesn't "save" any threads while allocating another task object and making debugging and exception handling harder by wrapping any exceptions in an AggregateException.
A task is a promise that something will produce some output in the future. That something may be :
A background operation running on a threadpool thread
A network/IO operation that doesn't run on any thread, waiting instead for the Network/IO driver to signal that the IO has finished.
A timer that signals a task after an interval. No kind of execution here.
A TaskCompletionSource that gets signalled after some time. No execution here either
HttpClient.GetAsync, HttpClient.GetStringAsync or Content.ReadAsStringAsync are such IO operations.
await doesn't make anything run asynchronously. It only awaits already executing tasks to complete without blocking.
Nothing is gained by using ContinueWith the way the second snippet does. This code simply allocates another task to wrap the task returned by ReadAsStringAsync. .Result returns the original task.
Should that method fail though, .Result will throw an AggregateException containing the original exception - or is it an AggregateException containing an AggregateException containing the original? I don't want to find out. Might as well have used Unwrap(). Finally, everything is still awaited.
The only difference is that the first snippet returns in the original synchronization context after each await. In a desktop application, that would be the UI. In many cases you want that - this allows you to update the UI with the response without any kind of marshalling. You can just write
var response = await client.GetAsync("www.someaddress.yo");
string content = await response.Content.ReadAsStringAsync();
textBox1.Text=content;
In other cases you may not want that, eg a library writer doesn't want the library to affect the client application. That's where ConfigureAwait(false) comes in :
var response = await client.GetAsync("www.someaddress.yo").ConfigureAwait(false);
string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
It's been 4 weeks since I dived into C# programming. It's really fun, however, I got a pain in the ass:
When I start a Task with HttpClient.PostAsync() alone, it works fine. But if I continue with something else, the orginal Task will be canceled, not by me. Looks like the Task is not happy about being continued.
Task<HttpResponseMessage> task0;
Task task1;
using (var client = new HttpClient())
{
HttpContent content = new ByteArrayContent(new byte[]{});
task0 = client.PostAsync("<valid http address>", content);
task1 = task0.ContinueWith((t) =>
{
// Do nothing
});
}
task1.Wait();
// I got task0.IsCanceled == true here
I tried:
1, Add task0.wait() immediately after PostAsync() will solve the issue but it's not what I want. Because I need the performance benefit from async and doing that will make it totally sync.
2, Add task0.wait() before task1.wait() will cause a TaskCanceledExcpetion.
3, Remove task1 and wait on task0 will be OK.
4, Call task0.start() will got "Start may not be called on a promise-style task."
So, plz someone tell me what am I doing wrong?
PS:
Before I asked this question, I had googled it for days. And some questions from StackOverflow might look relevent, but it turned out they were not the same to mine.
Who canceled my Task? She/He was asking why the continuation task wasn't executed.
Why does TaskCanceledException occur? She/He was messing up with the CancellationToken which I never did and got unexpected result.
I've also read this Task Cancellation and still got no clue.
Your HttpClient most likely get's disposed before PostAsync is finished. Remove using statement for test purposes, and everything will work as expected. You should dispose your client at a different point, when request is finished.
Also, many would recommend reuse single instance of HttpClient as much as possible, if your application logic allows it.
So, this code appears to be disposing the HttpClient as soon as you hook up the continuation, which is most likely not what you want.
If you want to use a using statement to dispose your client instance, you need to use the async and await keywords. The following code is equivalent to your example, with the compiler hooking up the continuation for you.
public async Task FooAsync()
{
using (var client = new HttpClient())
{
HttpContent content = new ByteArrayContent(new byte[]{});
await client.PostAsync("<valid http address>", content);
// Continue your code here.
}
}
If you want to continue using continuations created without the compiler's help, you can put the disposing logic in a continuation:
Task<HttpResponseMessage> task0;
Task task1;
var client = new HttpClient();
HttpContent content = new ByteArrayContent(new byte[]{});
task0 = client.PostAsync("<valid http address>", content);
task1 = task0.ContinueWith((t) =>
{
client.Dispose();
})
task1.Wait();
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();
});
I have a situation where I am making an async call to a method that returns and IDisposable instance. For example:
HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://www.google.com"));
Now before async was on the scene, when working with an IDisposable instance, this call and code that used the "response" variable would be wrapped in a using statement.
My question is whether that is still the correct approach when the async keyword is thrown in the mix? Even though the code compiles, will the using statement still work as expected in both the examples below?
Example 1
using(HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://www.google.com")))
{
// Do something with the response
return true;
}
Example 2
using(HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://www.google.com")))
{
await this.responseLogger.LogResponseAsync(response);
return true;
}
Yes, that should be fine.
In the first case, you're really saying:
Asynchronously wait until we can get the response
Use it and dispose of it immediately
In the second case, you're saying:
Asynchronously wait until we can get the response
Asynchronously wait until we've logged the response
Dispose of the response
A using statement in an async method is "odd" in that the Dispose call may execute in a different thread to the one which acquired the resource (depending on synchronization context etc) but it will still happen... assuming the thing you're waiting for ever shows up or fail, of course. (Just like you won't end up calling Dispose in non-async code if your using statement contains a call to a method which never returns.)
I have a call I am making from inside a xaml-based, C# metro application on the Win8 CP; this call simply hits a web service and returns JSON data.
HttpMessageHandler handler = new HttpClientHandler();
HttpClient httpClient = new HttpClient(handler);
httpClient.BaseAddress = new Uri("http://192.168.1.101/api/");
var result = await httpClient.GetStreamAsync("weeklyplan");
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(WeeklyPlanData[]));
return (WeeklyPlanData[])ser.ReadObject(result);
It hangs at the await but the http call actually returns almost immediately (confirmed through fiddler); it is as if the await is ignored and it just hangs there.
Before you ask - YES - the Private Network capability is turned on.
Any ideas why this would hang?
Check out this answer to my question which seems to be very similar.
Something to try: call ConfigureAwait(false) on the Task returned by GetStreamAsync(). E.g.
var result = await httpClient.GetStreamAsync("weeklyplan")
.ConfigureAwait(continueOnCapturedContext:false);
Whether or not this is useful depends on how your code above is being called - in my case calling the async method using Task.GetAwaiter().GetResult() caused the code to hang.
This is because GetResult() blocks the current thread until the Task completes. When the task does complete it attempts to re-enter the thread context in which it was started but cannot because there is already a thread in that context, which is blocked by the call to GetResult()... deadlock!
This MSDN post goes into a bit of detail on how .NET synchronizes parallel threads - and the answer given to my own question gives some best practices.
Just a heads up - if you miss the await at the top level in an ASP.NET controller, and you return the task instead of the result as a response, it actually just hangs in the nested await call(s) with no errors. A silly mistake, but had I seen this post it might have saved me some time checking through the code for something odd.
Disclaimer: I don't like the ConfigureAwait() solution because I find it non-intuitive and hard to remember. Instead I came to the conclusion to wrap non awaited method calls in Task.Run(() => myAsyncMethodNotUsingAwait()). This seems to work 100% but might just be a race condition!? I'm not so sure what is going on to be honest. This conclusion might be wrong and I risk my StackOverflow points here to hopefully learn from the comments :-P. Please do read them!
I just had the problem as described and found more info here.
The statement is: "you can't call an asynchronous method"
await asyncmethod2()
from a method that blocks
myAsyncMethod().Result
In my case I couldn't change the calling method and it wasn't async. But I didn't actually care about the result. As I remember it also didn't work removing the .Result and have the await missing.
So I did this:
public void Configure()
{
var data = "my data";
Task.Run(() => NotifyApi(data));
}
private async Task NotifyApi(bool data)
{
var toSend = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
await client.PostAsync("http://...", data);
}
In my case I didn't care about the result in the calling non-async method but I guess that is quite common in this use case. You can use the result in the calling async method.