Home > Back-end >  C# exception on cancellation of background task
C# exception on cancellation of background task

Time:09-18

I have a simple HttpClient downloading solution where I need to support cancel download. Download itself works perfectly, however when I attempt to cancel download, I receive following exception:

Cannot access a disposed object. Object name: 'SslStream'

My code is the following:

var cts = new CancellationTokenSource();
var client = new HttpClient() { Timeout = TimeSpan.FromMinutes(5) };

DownloadButton.Click  = async (s, e) => {
    var LocalPath = Path.Combine(AppContext.BaseDirectory, "index-5200-00.fits");
    if (!File.Exists(LocalPath)) {
        using (var fs = new FileStream(LocalPath, FileMode.Create, FileAccess.Write))
            using (var msg = await client.GetAsync(link1, cts.Token))
                await msg.Content.CopyToAsync(fs, cts.Token);
        Status = "Downloaded!";
    }
};

CancelButton.Click  = (s, e) => {
    if (!cts.IsCancellationRequested) cts.Cancel();
};

Question is, how to properly handle the download cancellation?

CodePudding user response:

I ended up with this code. It works exactly as expected:

var cts = new CancellationTokenSource();
var client = new HttpClient() { Timeout = TimeSpan.FromMinutes(5) };

DownloadButton.Click  = async (s, e) => {
    var LocalPath = Path.Combine(AppContext.BaseDirectory, "index-5200-00.fits");
    if (!File.Exists(LocalPath)) {
        try {
            using (var fs = new FileStream(LocalPath, FileMode.Create, FileAccess.Write))
            using (var stream = await client.GetStreamAsync(link1, cts.Token))
                await stream.CopyToAsync(fs, cts.Token);
            Text = "Downloaded!";
        }
        catch (TaskCanceledException) {
            if (File.Exists(LocalPath)) File.Delete(LocalPath);
        }
        catch (Exception ex) {
            Text = ex.Message;
        }
    }
};

CancelButton.Click  = (s, e) => {
    cts.Cancel();
};

CodePudding user response:

Add a try before any async call first, then,

Be sure to register a callback: cancellationToken.Register(client.CancelAsync);

then when running the method await msg.Content.CopyToAsync(fs, cts.Token);

On the catch block you can handle the cancelation as follows:

catch (WebException ex) when (ex.Status == WebExceptionStatus.RequestCanceled)
            {
                throw new OperationCanceledException();
            }               
            catch (TaskCanceledException)
            {
                throw new OperationCanceledException();
            }
  • Related