1

I need to call a HttpClient method with CancellationToken:

var result = await client.GetAsync(url, token);

I have something like this in my method:

public async Task<bool> CheckHashAsync(string cpf, string hash, CancellationToken token)
{
     HttpClient client = new HttpClient();
     client.BaseAddress = new Uri(ApiUrls.Base);
     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

     var url = $"{ApiUrls.DeviceCheck}/{cpf}/{hash}";
     var result = await client.GetAsync(url, token);

     if (result.IsSuccessStatusCode)
     {
         ...
     }

     return false;
}

If I call the method like this, it works:

CancellationTokenSource cts = new CancellationTokenSource(); 
cts.CancelAfter(TimeSpan.FromSeconds(Base.TASK_CANCELED_LOGIN_TIME));

await Base.Instance.CheckHashAsync(cpf, hash, cts.Token);

But, if create the CancellationTokenSource like this:

ctsTwo = GetCancellationToken("Login");

public static CancellationTokenSource GetCancellationToken(string action)
{
    switch(action)
    {
        case "Login":
            {
                CancellationTokenSource cts = new CancellationTokenSource();                        
                cts.CancelAfter(TimeSpan.FromSeconds(TASK_CANCELED_LOGIN_TIME));
                return cts;                        
            }
     }
}

And then call the method, it doesn't work:

await Base.Instance.CheckHashAsync(cpf, hash, ctsTwo.Token);

As soon as it calls the GetAsync method, it return a TaskCancelledException like the CancelAfter method was not set.

Can anyone explain why this happens?

gregoryp
  • 920
  • 4
  • 15
  • 35
  • If your only purpose for using the `CancellationToken` is to cancel the request after a some time, you should probably use `HttpClient.Timeout` instead. If you continue using `CancellationTokenSource`, make sure you call its `Dispose` method at some point. – Knelis Dec 07 '17 at 10:47
  • @Knelis So, this: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/cancel-an-async-task-or-a-list-of-tasks and this https://stackoverflow.com/questions/10134310/how-to-cancel-a-task-in-await are both wrong? – gregoryp Dec 07 '17 at 10:52
  • Ensure that all timeouts are right (that TASK_CANCELED_LOGIN_TIME is not too short) - your code should work in both cases. If it still doesn't - you have to produce minimal reproducable example. – Evk Dec 07 '17 at 10:56
  • @perozzo I don't see how my comment contradicts what is written on those pages. The [docs](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=netframework-4.7.1) explicitly state to 'Call the Dispose method when you are finished with the CancellationTokenSource object.' `CancellationToken` is useful if you also want to cancel the task some other way, but if your *only* purpose is a timeout, then I'd recommend using `HttpClient.Timeout`. – Knelis Dec 07 '17 at 10:58
  • @Evk TASK_CANCELED_LOGIN_TIME = 30. Everything is ok at this point. – gregoryp Dec 07 '17 at 10:59
  • @Knelis they said to use CancellationToken and you say to use HttpClient.Timeout. Which one is the correct to use? – gregoryp Dec 07 '17 at 11:00
  • Here's what the [docs](https://msdn.microsoft.com/en-us/library/system.net.http.httpclient.timeout%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396) say for `HttpClient.Timeout`: 'The same timeout will apply for all requests using this HttpClient instance. You may also set different timeouts for individual requests using a CancellationTokenSource on a task. Note that only the shorter of the two timeouts will apply.' – Knelis Dec 07 '17 at 11:01
  • @Knelis that's awesome. thank you very much for your explanation. – gregoryp Dec 07 '17 at 11:02

0 Answers0