Home > Software design >  How can I cancel and pause/resume web client download async?
How can I cancel and pause/resume web client download async?

Time:10-21

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using unfreez_wrapper;

namespace Downloads
{
    public partial class Form1 : Form
    {
        List<string> urls = new List<string>();
        DownloadProgressTracker tracker;
        long myLong = 0;
        WebClient client;

        public Form1()
        {
            InitializeComponent();

            tracker = new DownloadProgressTracker(50, TimeSpan.FromMilliseconds(500));

            lblDownloadProgress.Text = "";
            lblStatus.Text = "Download Pending";
            lblAmount.Text = "";
            lblSpeed.Text = "";
            urls.Add("https://speed.hetzner.de/10GB.bin");
            urls.Add("https://speed.hetzner.de/100MB.bin");
        }

        private async Task DownloadAsync()
        {
            using (var client = new WebClient())
            {
                this.client = client;

                client.DownloadFileCompleted  = (s, e) =>
                {
                    if (e.Cancelled)
                    {
                        client.Dispose();
                        return;
                    }
                };

                client.DownloadFileCompleted  = (s, e) => lblStatus.Text = "Download File Completed.";
                client.DownloadProgressChanged  = (s, e) => tracker.SetProgress(e.BytesReceived, e.TotalBytesToReceive);
                client.DownloadProgressChanged  = (s, e) => lblAmount.Text = SizeSuffix(e.BytesReceived)   "/"   SizeSuffix(e.TotalBytesToReceive);
                client.DownloadProgressChanged  = (s, e) =>  lblSpeed.Text = tracker.GetBytesPerSecondString();
                client.DownloadProgressChanged  = (s, e) => myLong = Convert.ToInt64(client.ResponseHeaders["Content-Length"]);
                client.DownloadProgressChanged  = (s, e) => progressBar1.Value = e.ProgressPercentage;
                client.DownloadProgressChanged  = (s, e) =>
                {
                    lblDownloadProgress.Text = "%"   e.ProgressPercentage.ToString();
                    lblDownloadProgress.Left = Math.Min(
                        (int)(progressBar1.Left   e.ProgressPercentage / 100f * progressBar1.Width),
                        progressBar1.Width - lblDownloadProgress.Width
                    );
                };

                for (int i = 0; i < urls.Count; i  )
                {
                    tracker.NewFile();

                    await client.DownloadFileTaskAsync(new Uri(urls[i]), @"d:\satImages\img"   i   ".gif");
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private async void btnStart_Click(object sender, EventArgs e)
        {
            lblStatus.Text = "Downloading...";
            await DownloadAsync();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            if (client != null)
            {
                client.CancelAsync();
                lblStatus.Text = "Download Stopped";
            }
        }

        static readonly string[] SizeSuffixes =
                   { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
        static string SizeSuffix(Int64 value, int decimalPlaces = 1)
        {
            if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); }
            if (value < 0) { return "-"   SizeSuffix(-value, decimalPlaces); }
            if (value == 0) { return string.Format("{0:n"   decimalPlaces   "} bytes", 0); }

            // mag is 0 for bytes, 1 for KB, 2, for MB, etc.
            int mag = (int)Math.Log(value, 1024);

            // 1L << (mag * 10) == 2 ^ (10 * mag) 
            // [i.e. the number of bytes in the unit corresponding to mag]
            decimal adjustedSize = (decimal)value / (1L << (mag * 10));

            // make adjustment when the value is large enough that
            // it would round up to 1000 or more
            if (Math.Round(adjustedSize, decimalPlaces) >= 1000)
            {
                mag  = 1;
                adjustedSize /= 1024;
            }

            return string.Format("{0:n"   decimalPlaces   "} {1}",
                adjustedSize,
                SizeSuffixes[mag]);
        }
    }
}

I didn't try the pause/resume part only the cancel.

At the top I added a WebClient global variable name client :

WebClient client;

In the download method I reference the client with the client in the method : And also checking if cancelled and dispose the client in the download method :

this.client = client;
    
                    client.DownloadFileCompleted  = (s, e) =>
                    {
                        if (e.Cancelled)
                        {
                            client.Dispose();
                            return;
                        }
                    };

In the btnStop click event I added this code :

if (client != null)
                {
                    client.CancelAsync();
                    lblStatus.Text = "Download Stopped";
                }

When it's downloading and I click stop button I'm getting this exception message :

Cacelled getting exception

CodePudding user response:

I believe that you need to wrap your WebClient transactions within a BackgroundWorker object, so that you can set WorkerSupportsCancellation to true before the cancellation. Then the cancellation should work without exception, I believe.

Please reference -

https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.backgroundworker?view=net-5.0

  • Related