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();
}