.NET HttpClient - Canceled Cancellation Token does not cancel the request

I am having a problem with the .NET HttpClient class (.NET 4.5.1, System.Net.Http v4.0.0.0). I call HttpClient.GetAsync passing in a CancellationToken (as part of a Nuget package that abstracts calls between webservices). If the token was canceled before the call, the request passes without exception. This behavior does not seem correct.

My test (incomplete, not completely written - without checking the exception):

 [TestMethod] public async Task Should_Cancel_If_Cancellation_Token_Called() { var endpoint = "nonexistent"; var cancellationTokenSource = new CancellationTokenSource(); var _mockHttpMessageHandler = new MockHttpMessageHandler(); _mockHttpMessageHandler .When("*") .Respond(HttpStatusCode.OK); var _apiClient = new ApiClientService(new HttpClient(_mockHttpMessageHandler)); cancellationTokenSource.Cancel(); var result = await _apiClient.Get<string>(endpoint, null, cancellationTokenSource.Token); } 

The method I am testing is:

 public async Task<T> Get<T>(string endpoint, IEnumerable<KeyValuePair<string, string>> parameters = null, CancellationToken cancellationToken = default(CancellationToken)) { var builder = new UriBuilder(Properties.Settings.Default.MyEndpointHost + endpoint); builder.Query = buildQueryStringFromParameters(parameters); _httpClient.DefaultRequestHeaders.Accept.Clear(); _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); try { // After this, we really shouldn't continue. var request = await _httpClient.GetAsync(builder.Uri, cancellationToken); if (!request.IsSuccessStatusCode) { if (request.StatusCode >= HttpStatusCode.BadRequest && request.StatusCode < HttpStatusCode.InternalServerError) { throw new EndpointClientException("Service responded with an error message.", request.StatusCode, request.ReasonPhrase); } if (request.StatusCode >= HttpStatusCode.InternalServerError && (int)request.StatusCode < 600) { throw new EndpointServerException("An error occurred in the Service endpoint.", request.StatusCode, request.ReasonPhrase); } } var json = await request.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject<T>(json); } catch (Exception ex) { throw; } } 

I know that I can check the status of the cancellation token before calling HttpClient.GetAsync and throw it if cancellation is requested. I know that I can register a delegate to cancel the HttpClient request. However, it seems that passing the marker to the HttpClient method should take care of this for me (or, what else, what is it?), So I wonder if I am missing something. I do not have access to the HttpClient source code.

Why HttpClient.GetAsync n't HttpClient.GetAsync check the cancel token and interrupt its process when I pass it?

+6
source share
1 answer

HttpClient does not check the cancellation token itself, it passes it to the message handler when it calls its SendAsync method. It then registers with the continuation of the task returned from SendAsync and will cancel its own task as canceled if the task returned by the message handler has been canceled.

So the problem in your scenario is your implementation of MockHttpMessageHandler , which does not seem to check the cancellation token.

Note that if HttpClient is called through its empty constructor, it internally uses the HttpClientHandler , which registers the delegate on the cancel token, which aborts the request and cancels the task.

+2
source

All Articles