在 "await DownloadTaskAsync" 上调用 WebClient.CancelAsync 时出现 WebException
WebException when calling WebClient.CancelAsync on "await DownloadTaskAsync"
这很好用:
private WebClient _webClient;
private void ButtonStart_Click(object sender, RoutedEventArgs e) {
using (_webClient = new WebClient()) {
_webClient.DownloadFileTaskAsync("https://speed.hetzner.de/100MB.bin", @"D:0MB.bin");
}
}
private void ButtonStop_Click(object sender, RoutedEventArgs e) {
_webClient.CancelAsync();
}
虽然此代码(注意 async/await 模式)...:[=17=]
private WebClient _webClient;
private async void ButtonStart_Click(object sender, RoutedEventArgs e) {
using (_webClient = new WebClient()) {
await _webClient.DownloadFileTaskAsync("https://speed.hetzner.de/100MB.bin", @"D:0MB.bin");
}
}
private void ButtonStop_Click(object sender, RoutedEventArgs e) {
_webClient.CancelAsync();
}
...抛出以下异常:
System.Net.WebException
The request was aborted: The request was canceled.
at System.Net.ConnectStream.EndRead(IAsyncResult asyncResult)
at System.Net.WebClient.DownloadBitsReadCallbackState(DownloadBitsState state, IAsyncResult result)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at WpfApp1.MainWindow.<ButtonStart_Click>d__2.MoveNext() in WpfApp1\MainWindow.xaml.cs:line 19
如何在不抛出异常的情况下取消以 await WebClient.DownloadFileTaskAsync()
开始的任务?
异常正是应该工作的方式。
如果您不希望该异常从您的事件处理程序传播出去,请捕获该异常。
你可以像这样捕获异常:
using (_webClient = new WebClient())
{
try
{
await _webClient.DownloadFileTaskAsync("https://speed.hetzner.de/100MB.bin", @"D:0MB.bin");
}
catch (WebException ex) when (ex.Status == WebExceptionStatus.RequestCanceled)
{
Console.WriteLine("Cancelled");
}
}
更新: 如何更改 CancelAsync
的默认行为,以避免必须捕获异常:
public static Task<bool> OnCancelReturnTrue(this Task task)
{
return task.ContinueWith(t =>
{
if (t.IsFaulted)
{
if (t.Exception.InnerException is WebException webEx
&& webEx.Status == WebExceptionStatus.RequestCanceled) return true;
throw t.Exception;
}
return t.IsCanceled;
}, TaskContinuationOptions.ExecuteSynchronously);
}
用法示例:
bool cancelled = await _webClient.DownloadFileTaskAsync(
"https://speed.hetzner.de/100MB.bin", @"D:0MB.bin").OnCancelReturnTrue();
if (cancelled) Console.WriteLine("Cancelled");
这很好用:
private WebClient _webClient;
private void ButtonStart_Click(object sender, RoutedEventArgs e) {
using (_webClient = new WebClient()) {
_webClient.DownloadFileTaskAsync("https://speed.hetzner.de/100MB.bin", @"D:0MB.bin");
}
}
private void ButtonStop_Click(object sender, RoutedEventArgs e) {
_webClient.CancelAsync();
}
虽然此代码(注意 async/await 模式)...:[=17=]
private WebClient _webClient;
private async void ButtonStart_Click(object sender, RoutedEventArgs e) {
using (_webClient = new WebClient()) {
await _webClient.DownloadFileTaskAsync("https://speed.hetzner.de/100MB.bin", @"D:0MB.bin");
}
}
private void ButtonStop_Click(object sender, RoutedEventArgs e) {
_webClient.CancelAsync();
}
...抛出以下异常:
System.Net.WebException
The request was aborted: The request was canceled.
at System.Net.ConnectStream.EndRead(IAsyncResult asyncResult)
at System.Net.WebClient.DownloadBitsReadCallbackState(DownloadBitsState state, IAsyncResult result)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at WpfApp1.MainWindow.<ButtonStart_Click>d__2.MoveNext() in WpfApp1\MainWindow.xaml.cs:line 19
如何在不抛出异常的情况下取消以 await WebClient.DownloadFileTaskAsync()
开始的任务?
异常正是应该工作的方式。
如果您不希望该异常从您的事件处理程序传播出去,请捕获该异常。
你可以像这样捕获异常:
using (_webClient = new WebClient())
{
try
{
await _webClient.DownloadFileTaskAsync("https://speed.hetzner.de/100MB.bin", @"D:0MB.bin");
}
catch (WebException ex) when (ex.Status == WebExceptionStatus.RequestCanceled)
{
Console.WriteLine("Cancelled");
}
}
更新: 如何更改 CancelAsync
的默认行为,以避免必须捕获异常:
public static Task<bool> OnCancelReturnTrue(this Task task)
{
return task.ContinueWith(t =>
{
if (t.IsFaulted)
{
if (t.Exception.InnerException is WebException webEx
&& webEx.Status == WebExceptionStatus.RequestCanceled) return true;
throw t.Exception;
}
return t.IsCanceled;
}, TaskContinuationOptions.ExecuteSynchronously);
}
用法示例:
bool cancelled = await _webClient.DownloadFileTaskAsync(
"https://speed.hetzner.de/100MB.bin", @"D:0MB.bin").OnCancelReturnTrue();
if (cancelled) Console.WriteLine("Cancelled");