如何取消 pause/resume Web 客户端异步下载?

How can I cancel and pause/resume web client download async?

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

我没有尝试 pause/resume 部分,只尝试了取消。

在顶部我添加了一个 WebClient 全局变量名称 client :

WebClient client;

在下载方法中,我在方法中引用了客户端: 并检查是否取消并在下载方法中处理客户端:

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

在 btnStop 点击事件中我添加了这段代码:

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

在下载并单击停止按钮时,我收到此异常消息:

Cacelled getting exception

我认为您需要将 WebClient 事务包装在 BackgroundWorker 对象中,以便您可以在取消之前将 WorkerSupportsCancellation 设置为 true。那么我相信取消应该无一例外地起作用。

请参考-

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