This is the original code that had been running fine for a few weeks. In a test I just did, it failed 0 out of 100 attempts.
using (var httpClient = new Http
Edit: unaccepting my own answer, but leaving it for reference. The code works, with a catch: ContinueWith loses the SynchronizationContext
Thanks to @jbl and @MattSmith for putting me on the right track.
The problem was indeed that Task.WhenAll
does not wait on the continuations. The solution is to set TaskContinuationOptions.AttachedToParent
.
So this
private static Task GetAsync(HttpClient httpClient, Uri URI, Action> continuationAction)
{
return httpClient.GetAsync(URI)
.ContinueWith(request =>
{
request.Result.EnsureSuccessStatusCode();
request.Result.Content.ReadAsAsync()
.ContinueWith(continuationAction);
});
}
becomes this
private static Task GetAsync(HttpClient httpClient, Uri URI, Action> continuationAction)
{
return httpClient.GetAsync(URI)
.ContinueWith(request =>
{
request.Result.EnsureSuccessStatusCode();
request.Result.Content.ReadAsAsync()
.ContinueWith(continuationAction, TaskContinuationOptions.AttachedToParent);
}, TaskContinuationOptions.AttachedToParent);
}
More info available on MSDN: Nested Tasks and Child Tasks