Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cancel Windows 10 BackgroundDownloader

I'd like to implement a timeout functionality for BackgroundDownloader. When I reach timeout i can't cancel download operation. So I use it like so:

   public async void downloadFile(string fileUrl, string fileName) {
        var myFolder = await StorageFolder.GetFolderFromPathAsync(Package.Current.InstalledLocation.Path);
        var myFile = await myFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);

        var downloader = new BackgroundDownloader();
        var downloadOperation = downloader.CreateDownload(new Uri(fileUrl), myFile);

        var task = Task.Run(async () => await downloadOperation.StartAsync().AsTask());
        if ( task.Wait(TimeSpan.FromMilliseconds(1000)) ) {
            // file is downloaded in time

        } else {
            // timeout is reached - how to cancel downloadOperation ?????

        }
    }

I was trying :

downloadOperation.StartAsync().Cancel();

I get

WinRT information: This operation was already started. Call AttachAsync to attach to a running download/upload.

downloadOperation.AttachAsync().Cancel();

I get

Exception thrown: 'System.Runtime.InteropServices.COMException' in Project.exe WinRT information: This operation was not started. Call StartAsync to start the operation.Additional information: A method was called at an unexpected time.

Any ideas will be apreciated!

like image 634
Vasile Doe Avatar asked Mar 13 '23 03:03

Vasile Doe


1 Answers

When I reach timeout i can't cancel download operation. I was trying : downloadOperation.AttachAsync().Cancel();

Based on my test, downloadOperation.AttachAsync().Cancel(); works fine on my site. Following is the code I used for testing:

public async void downloadFile(string fileUrl, string fileName)
{
    var myFolder = await StorageFolder.GetFolderFromPathAsync(Package.Current.InstalledLocation.Path);
    var myFile = await myFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);

    var downloader = new BackgroundDownloader();
    var downloadOperation = downloader.CreateDownload(new Uri(fileUrl), myFile);

    var task = Task.Run(async () => await downloadOperation.StartAsync().AsTask());
    if (task.Wait(TimeSpan.FromMilliseconds(1000)))
    {
        // file is downloaded in time
    }
    else {
        // timeout is reached - how to cancel downloadOperation ?????
        downloadOperation.AttachAsync().Cancel();
    }
}

Usually we use CancellationToken to cancel the download operation. Besides, using Task.Wait method will block UI thread, and this causes a bad user experience. So using CancellationTokenSource.CancelAfter method may be a better choice in your scenario.

Following is the code I have verified:

public async void downloadFile(string fileUrl, string fileName)
{
    var myFolder = await StorageFolder.GetFolderFromPathAsync(Package.Current.InstalledLocation.Path);
    var myFile = await myFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);

    var downloader = new BackgroundDownloader();
    var downloadOperation = downloader.CreateDownload(new Uri(fileUrl), myFile);

    // Define the cancellation token.
    CancellationTokenSource cts = new CancellationTokenSource();
    CancellationToken token = cts.Token;

    cts.CancelAfter(1000);
    try
    {
        // Pass the token to the task that listens for cancellation.
        await downloadOperation.StartAsync().AsTask(token);
        // file is downloaded in time
    }
    catch (TaskCanceledException)
    {
        // timeout is reached, downloadOperation is cancled
    }
    finally
    {
        // Releases all resources of cts
        cts.Dispose();
    }
}
like image 151
Jerry Li Avatar answered Mar 25 '23 09:03

Jerry Li