在等待下载完成时取消WebClient下载



寻找更普遍可接受的等待 WebClient的模式:

  • 下载文件(可能需要几百毫秒或几分钟(
  • 等待下载完成之前完成任何其他工作
  • 定期检查另一堂课的标志(布尔(并取消下载,如果需要(无法修改此类(

约束:

  • 除非是 Task.Run(async () => await method())
  • 的线条,否则不能使用异步/等待
  • 当调用Download方法时,它只需要像返回字符串的普通方法一样行为
  • 可以使用.NET 4.5和Roslyn编译器的任何功能
  • 是否使用WebClient.DownloadFileTaskAsyncDownloadFileAsync没有区别;只需要使用WebClient
  • 取消下载的能力

当前的实现似乎正在起作用,但似乎并不正确。与使用while循环和Thread.Sleep相比,使用CC_1时会定期检查otherObject.ShouldCancel

private string Download(string url)
{
    // setup work
    string fileName = GenerateFileName();
    // download file
    using (var wc = new WebClient()) 
    {
        wc.DownloadFileCompleted += OnDownloadCompleted
        Task task = wc.DownloadFileTaskAsync(url, fileName);
        // Need to wait until either the download is completed
        // or download is canceled before doing any other work
        while (wc.IsBusy || task.Status == TaskStatus.WaitingForActivation) 
        {
            if (otherObject.ShouldCancel) 
            {
                wc.CancelAsync();
                break;
            }
            Thread.Sleep(100);
        }
        void OnDownloadCompleted(object obj, AsyncCompletedEventArgs args)
        {
            if(args.Cancelled)
            {
                // misc work
                return;
            }
            // misc work (different than other work below)
        }
    }
    // Other work after downloading, regardless of cancellation.
    // Could include in OnDownloadCompleted as long as this
    // method blocked until all work was complete
    return fileName;
}

我希望这很有帮助。基本上,您的包装器使用concellationToken.Register(webclient.cancel(注册回调;一旦调用comcellationToken.cancel((,异步任务应抛出一个例外,您可能会处理以下操作:

public class Client
{
    public async Task<string> DownloadFileAsync(string url, string outputFileName, CancellationToken cancellationToken)
    {
        using (var webClient = new WebClient())
        {
            cancellationToken.Register(webClient.CancelAsync);
            
            try
            {
                var task = webClient.DownloadFileTaskAsync(url, outputFileName);
                await task; // This line throws an exception when cancellationTokenSource.Cancel() is called.
            }
            catch (WebException ex) when (ex.Status == WebExceptionStatus.RequestCanceled)
            {
                throw new OperationCanceledException();
            }
            catch (AggregateException ex) when (ex.InnerException is WebException exWeb && exWeb.Status == WebExceptionStatus.RequestCanceled)
            {
              throw new OperationCanceledException();
            }
            catch (TaskCanceledException)
            {
                throw new OperationCanceledException();
            }
            return outputFileName;
        }
    }
}

尝试此示例的简单方法

    private async static void DownloadFile()
    {
        var cancellationTokenSource = new CancellationTokenSource();
        var client = new Client();
        var task = client.DownloadFileAsync("url",
            "output.exe", cancellationTokenSource.Token);
        cancellationTokenSource.Token.WaitHandle.WaitOne(TimeSpan.FromSeconds(5));
        cancellationTokenSource.Cancel();
        try
        {
            var result = await task;
        }
        catch (OperationCanceledException)
        {
            // Operation Canceled
        }
    }

在更现实的场景中,concellationTokenSource.cancel((将由用户互动或回调引起的事件调用。

update

另一种方法是订阅下载progresschanged事件,并检查其他访问时。

这是一个示例:

public class Client
{
    public string Download(string url)
    {
        // setup work
        string fileName = GenerateFileName();
        // download file
        using (var wc = new WebClient())
        {
            wc.DownloadProgressChanged += OnDownloadProgressChanged;
            wc.DownloadFileCompleted += OnDownloadFileCompleted;
            DownloadResult downloadResult = DownloadResult.CompletedSuccessfuly;
            void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
            {
                if (otherObject.ShouldCancel)
                {
                    ((WebClient)sender).CancelAsync();
                }
            }
            void OnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
            {
                if (e.Cancelled)
                {
                    downloadResult = DownloadResult.Cancelled;
                    return;
                }
                if (e.Error != null)
                {
                    downloadResult = DownloadResult.ErrorOccurred;
                    return;
                }
            }
            try
            {
                Task task = wc.DownloadFileTaskAsync(url, fileName);
                task.Wait();
            }
            catch (AggregateException ex)
            {
            }
            switch (downloadResult)
            {
                case DownloadResult.CompletedSuccessfuly:
                    break;
                case DownloadResult.Cancelled:
                    break;
                case DownloadResult.ErrorOccurred:
                    break;
            }
        }
        // Other work after downloading, regardless of cancellation.
        // Could include in OnDownloadCompleted as long as this
        // method blocked until all work was complete
        return fileName;
    }
}
public enum DownloadResult
{
    CompletedSuccessfuly,
    Cancelled,
    ErrorOccurred
}

相关内容

  • 没有找到相关文章

最新更新