Cancel an 'HttpClient' POST request
Asked Answered
B

3

5

I am uploading an image with HttpClient.PostAsync() on my Windows Phone 8 app. The user has the option to cancel this upload via a UI button.

To cancel the POST request, I set a CancellationToken. But this doesn't work. After the cancellation request, I see still see the upload taking place in my proxy and it is evident that the request was ignored. My code:

using (var content = new MultipartFormDataContent())
{
    var file = new StreamContent(stream);
    file .Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
    {
        FileName =  "filename.jpg",
    };
    file.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
    content.Add(file);

    await httpclient.PostAsync(new Uri("myurl", UriKind.Absolute), content,
        cancellationToken);
}

Please also note that I have a CancellationTokenSource for the CancellationToken. After the user clicks on the Cancel button, tokensource.Cancel() is called. Also, the images in my testcase are from 1 to 2 MB (not that big).

So, is there a way to cancel an HttpClient POST request?

Beiderbecke answered 17/7, 2015 at 8:20 Comment(3)
From this answer: "There is no guarantee that cancelling the CancelationTokenSource will cancel the underlying operation. It depends upon the implementation of the underlying operation (in this case SendAsync method). Operation could be canceled immediately, or after few seconds, or never." So, based on that, it appears that after making the PostAsync() request, you may need to check cancellationToken.IsCancellationRequested, and if true, call DeleteAsync() on the uploaded image.Scapegrace
Though you specified windows-phone-8, you didn't specify whether you are using Windows.Web.Http.HttpClient or System.Net.Http.HttpClient. (Based on the parameters provided to your PostAsync() call, it appears to be the latter.)Scapegrace
Related: Properly Abort or Cancel PostAsyncScapegrace
A
4
try
{
    var client = new HttpClient();

    var cts = new CancellationTokenSource();
    cts.CancelAfter(3000); // 3 seconds

    var request = new HttpRequestMessage();

    await client.PostAsync(url, content, cts.Token);
}
catch(OperationCanceledException ex)
{
    // timeout has been hit
}
Arran answered 20/11, 2017 at 13:43 Comment(1)
Can you explain why this would abort the underlying operation?Rictus
N
0

Cancelling a task doesn't terminate it instantly. You have to check manually before doing your work by checking the token's status:

if (ct.IsCancellationRequested) 
{
    ct.ThrowIfCancellationRequested();
}

// Post request here...

This article is quite useful: How to: Cancel a Task and Its Children

Nowicki answered 17/7, 2015 at 13:27 Comment(1)
I do that. My problem is, I want to cancel an upload who has already started (I see the upload traffic in my proxy). although my app stops the work and also the breakpoint on the httpclient response don't fire... the image is uploadedBeiderbecke
H
0

In implementations of HttpClient for Mono like in Xamarin, the get & post methods don't honor the cancellation token if the host is not reachable, and wait up to 2 minutes before failing. This is perhaps why CancellationTokenSource with a CancelAfter does not work here.

To fix this, the simplest method I found was using the Polly library https://github.com/App-vNext/Polly

var policy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(3000),
    TimeoutStrategy.Pessimistic,
    (context, timespan, task) => throw new Exception("Cannot connect to server."));

await policy.ExecuteAsync(async () =>
{
    var httpClient = new HttpClient();
    var response = await httpClient.PostAsync(...);
    response.EnsureSuccessStatusCode();
    ...
});
Hands answered 28/5, 2022 at 22:59 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.