【发布时间】:2023-03-10 12:25:01
【问题描述】:
寻找更普遍接受的等待WebClient 的模式:
- 下载文件(可能需要几百毫秒或几分钟)
- 等待下载完成,然后再执行任何其他工作
- 定期检查另一个类的标志 (bool) 并在需要时取消下载(不能修改此类)
约束:
- 不能使用 async/await,除非它类似于
Task.Run(async () => await method()) - 当
Download方法被调用时,它只需要表现得像一个返回字符串的普通方法 - 可以使用 .Net 4.5 和 Roslyn 编译器的任何功能
- 使用
WebClient.DownloadFileTaskAsync或DownloadFileAsync没有区别;只需要能够根据需要使用WebClient取消下载
当前的实现似乎正在运行,但似乎不太正确。在使用WebClient 时,是否有比使用while 循环和Thread.Sleep 定期检查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;
}
【问题讨论】:
-
您是否尝试过传入 CancellationToken 参数,然后使用 cancelToken.Register(webClient.CancelAsync);?
-
我会说 while-sleep 循环可以满足您的要求。由于
Download应该是同步的 - 在等待下载完成时它无关紧要,所以为什么不同时轮询该标志。当然,您可以在所有这些之上添加一些花哨的东西,但这不会有太大变化。 -
@KhaledElKholy -
otherObject.ShouldCancel是否仍需要定期轮询以向cancellationToken.Cancel()发出信号? -
不,cancellationTokenSource.Cancel() 将导致 webClient.Cancel() 被调用,您已将其注册为回调,然后导致异步任务抛出 WebException 或 TaskCanceledException。另外,为什么不将 cancelTokenSource 实例传递给 otherObject 以便它可以调用 cancelTokenSource.Cancel() 而不必定期检查 otherObject.ShouldCancel 属性?你可以访问 otherObject 的类型内部实现吗?
-
@KhaledElKholy - 我无法修改
otherObject中的任何内容(请参阅问题,第三个要点)。
标签: c# webclient cancellation webclient-download