Why does this async code sometimes fail, and only when not observed?

后端 未结 3 1740
情书的邮戳
情书的邮戳 2021-01-19 15:59

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         


        
3条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-01-19 16:22

    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

提交回复
热议问题