Await HttpClient.GetStringAsync() and cancellation
I’m a big fan of supporting cancellation on async methods. I was recently wondering how to do this for HttpClient.GetStringAsync(). This post has some answers.
Async Function TestAsync(uri As Uri, Optional cancel As CancellationToken = Nothing
) As Task(Of String)
Dim client As New HttpClient
Return Await client.GetStringAsync(uri, cancel)
' error: no overload of GetStringAsync takes a cancellation token
End Function
My first attempt is above. But it doesn’t compile, because HttpClient.GetStringAsync doesn’t have any overloads that take a CancellationToken.
The answer? Instead of using GetStringAsync, we have to use GetAsync, which does take a cancellation-token parameter:
Dim client As New HttpClient
Using response = Await client.GetAsync(uri,
HttpCompletionOption.ResponseContentRead,
cancel)
Return Await response.Content.ReadAsStringAsync()
End Using
The “ResponseContentRead” option can be omitted, since it is the default for calls to HttpClient.GetAsync. I included it just for clarity. What it means is that the entire body of the response is read by the call to HttpClient.GetAsync(), and so is subject to the cancellation token. Therefore the next call to ReadAsStringAsync() will complete immediately and needn’t worry about cancellation.
If you wanted to use the option “ResponseHeaderRead” instead, then cancellation looks different:
Try
Using response = Await client.GetAsync(uri,
HttpCompletionOption.ResponseHeadersRead,
cancel)
Using cancelreg = cancel.Register(Sub() response.Dispose())
Return Await response.Content.ReadAsStringAsync()
End Using
End Using
Catch ex As ObjectDisposedException
If cancel.IsCancellationRequested Then Throw New OperationCanceledException
Throw
End Try
Explanation: in this case, only the headers of the response are read by HttpClient.GetAsync(), and so only they are subject to cancellation by the cancellation token. When we next invoke ReadAsStringAsync(), this operation might take a long time, and so we need to figure out how to cancel it. No overload of ReadAsStringAsync() takes a cancellation token. The best we can do is dispose of the HttpResponseMessage. This will cause the ReadAsStringAsync() method to terminate abruptly with an ObjectDisposedException.
Comments
Anonymous
December 08, 2012
thx!Anonymous
February 06, 2014
Fantastic. I really needed this.Anonymous
October 21, 2015
wow, very cool, just what I needed!!! thanks for the explanation and saving a bunch of my time!Anonymous
November 14, 2015
How to cancel GetStreamAsync then?Anonymous
April 10, 2016
Great, thanks!