How to Cancel an HttpClient Request in C#

By FoxLearn 1/21/2025 8:47:28 AM   23
In C#, you can achieve this by using the CancellationToken with the HttpClient class.

Sending Requests with Cancellation Support

To support cancellation in an HttpClient request, the first step is to pass a CancellationToken to the GetAsync or PostAsync method.

For example, How to define a method to send an HTTP request:

private static async Task SendRequest(CancellationToken cancellationToken)
{
    var response = await httpClient.GetAsync("https://localhost:5000/stocks/MSFT", cancellationToken);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}

Creating a CancellationTokenSource

A CancellationTokenSource is required to generate a CancellationToken. The CancellationToken is what you pass to your SendRequest method to control the cancellation process.

CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
await SendRequest(cancellationTokenSource.Token);

Cancelling the Request

To cancel the HTTP request, simply call the Cancel method on the CancellationTokenSource:

cancellationTokenSource.Cancel();

To make this work with a UI, such as a cancel button, you'll need to make the CancellationTokenSource object available to the event handler for the button's click event.

Disposing of the CancellationTokenSource

Once you're done using the CancellationTokenSource, it’s important to dispose of it properly to free up resources. Since you're likely sharing the CancellationTokenSource object across different parts of your application, especially in UI-based code, you won’t use a using block to dispose of it. Instead, manually dispose of it when it's no longer needed:

cancellationTokenSource.Dispose();

Handling Task Cancellations

When you cancel an HTTP request, the HttpClient will throw a TaskCanceledException. This exception can also occur when a request times out. To differentiate between a user cancellation and a timeout, you can check the IsCancellationRequested property of the CancellationToken.

try
{
    var response = await httpClient.GetAsync("https://localhost:5000/stocks/MSFT", cancellationToken);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}
catch (TaskCanceledException) when (cancellationToken.IsCancellationRequested)
{
    Console.WriteLine("User canceled request");
}
catch (TaskCanceledException)
{
    Console.WriteLine("Request timed out");
}

Handling Cancellation During Deserialization

Often, an HttpClient request will require two main steps: sending the request and deserializing the response. To ensure that cancellation works throughout this process, including during deserialization, you can use the JsonSerializer.DeserializeAsync method with the cancellation token. This requires deserializing from a stream, so you'll need to use Content.ReadAsStreamAsync() to obtain the response content.

using System.Text.Json;

var response = await httpClient.GetAsync("https://localhost:5000/stocks/MSFT", cancellationToken);
response.EnsureSuccessStatusCode();

// Check if cancellation was requested before performing an expensive operation
cancellationToken.ThrowIfCancellationRequested();

using (var stream = await response.Content.ReadAsStreamAsync())
{
    return await JsonSerializer.DeserializeAsync<Stock>(stream, jsonOptions, cancellationToken);
}

In this example, cancellationToken.ThrowIfCancellationRequested() ensures that the cancellation is checked before performing the deserialization operation. This is especially important for time-consuming operations, as it allows you to exit early if the user has canceled the request.

By using CancellationToken and CancellationTokenSource, you can easily allow users to cancel requests at any point in time, whether during the request itself or while deserializing the response.