Damn Vegetables
Damn Vegetables

Reputation: 12504

Accessing HttpClient in multiple tasks causes "The request was canceled" exceptions

I am creating an application that consumes REST API's. I wrapped the HTTP calls in a class like this. There are many similar methods in this class. I reuse the same HttpClient instance for all methods, as StackOverflow answers said it was meant to be reused and designed thread-safe.

public async Task<DataType> GetData()
{
    var address = "XXX";
    var res = await Client.GetAsync(address).ConfigureAwait(false);
    var data = res.Content.ReadAsStringAsync().Result;
    return data;
}

I use timers to call API's regularly (each timer calls a different API). When there is only one timer, the programme seems to run well. But when there are two timers, System.Net.Http.HttpRequestException keeps happening at the second line.

System.Net.Http.HttpRequestException: 'An error occurred while sending the request.'
Inner Exception
WebException: The request was aborted: The request was canceled

Inner trace:

at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)

Outer trace:

at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()

What does it mean the request was cancelled? It is not related to the web server side, right? Do I need to take care of something when calling HttpClient in multiple threads (Tasks)?

Update

After seeing the traffic with an HTTP analyser, I found that the same HTTP requests (which supposed to be made only once at a time) were made very many at once. I started the task at a selection changed event of a third-party UI control. And for some reason, the UI control raised selection changed events very quickly when actually the selection was not changed. I am investigating the cause, and if that is the reason, I may have to close this question.

Update 2

I found out a way to suppress those redundant selection changed events and now the exception does not occur. I tried to delete the question, but the warning said that Stack Overflow did not recommend doing so, and if I kept doing it, I might be blocked from Stack Overflow. Closing options did not fit the real reason, so I will leave this. It might be helpful to someone with similar problems in the future.

Upvotes: 3

Views: 2052

Answers (1)

Drawaes
Drawaes

Reputation: 194

You should not call the .Result instead

public async Task<DataType> GetData()
{
    var address = "XXX";
    var res = await Client.GetAsync(address).ConfigureAwait(false);
    var data = await res.Content.ReadAsStringAsync().ConfigureAwait(false);
    return data;
}

The issue here is you are offloading the await on the first async (ConfigureAwait(false)) but then calling .Result on the second. I can't tell without seeing the rest of the application but you maybe deadlocking on the .Result call.

Stephan Cleary's: Article on why you shouldn't block on Async Code

Upvotes: 4

Related Questions