多个任务.当WPF应用程序中出现第一个异常时,所有任务都终止
本文关键字:任务 异常 终止 第一个 WPF 应用程序 | 更新日期: 2024-07-23 09:41:48
以下示例代码片段通过使用async/await
编码技术读取/处理Web Url示例列表List<string> urls
的内容来实现多任务处理功能(类似于MSDN演示示例:https://msdn.microsoft.com/en-us/library/jj155756.aspx)。出于测试目的,Url List<string> urls
包含两个错误项。
清单1。WPF异步/等待多任务实现中的错误处理
namespace ProcessTasksAsTheyFinish
{
public partial class MainWindow : Window
{
CancellationTokenSource cts;
// sample Url list containing erroneous items
private List<string> SetUpURLList()
{
List<string> urls = new List<string>
{
"http://msdn.microsoft.com",
"http://msdn.microsoft.com/library/windows/apps/br211380.aspx",
"error1",
"http://msdn.microsoft.com/en-us/library/aa578028.aspx",
"error2",
"http://msdn.microsoft.com/en-us/library/ms404677.aspx",
"http://msdn.microsoft.com/en-us/library/ff730837.aspx"
};
return urls;
}
public MainWindow() { InitializeComponent(); }
private async void startButton_Click(object sender, RoutedEventArgs e) {
resultsTextBox.Clear();
cts = new CancellationTokenSource();
try { await AccessTheWebAsync(cts.Token);}
finally { cts = null; }
}
private async Task AccessTheWebAsync(CancellationToken ct) {
try {
HttpClient client = new HttpClient();
// sample list of web addresses
List<string> urlList = SetUpURLList();
// query to create a collection of Tasks
IEnumerable<Task<int>> downloadTasksQuery =
from url in urlList select ProcessURL(url, client, ct);
// run multiple Tasks in async mode
await Task.WhenAll(downloadTasksQuery.ToList());
resultsTextBox.Text += "'r'nDownloads complete.";
}
catch (OperationCanceledException){
resultsTextBox.Text += "'r'nDownloads canceled.";
}
catch (Exception ex){
resultsTextBox.Text += Environment.NewLine + ex.Message;
}
}
private async Task<int> ProcessURL(string url, HttpClient client, CancellationToken ct)
{
try
{
HttpResponseMessage response = await client.GetAsync(url, ct);
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
resultsTextBox.Text += String.Format("'r'nLength: {0}", urlContents.Length);
return urlContents.Length;
}
catch
{
//if (cts != null) cts.Cancel();
throw;
}
}
}
}
// sample output:
// Length: 196315
// Length: 468941
// Length: 158496
// Length: 200790
// Length: 48022
// An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.
输出包含为5个有效Url计算的长度信息和与异常ex.Message
相对应的错误通知。
目标是以这样的方式修改功能,即第一个异常将完全终止await Task.WhenAll
的多任务执行。换句话说,实现与等待的多个Tasks
相关的那种"要么全有要么全无"的业务逻辑。
在本例中,它是通过使用CancellationToken
(如清单1中的注释行所示)向Exception
处理块添加以下语句来实现的:
if (cts != null) cts.Cancel();
输出文本看起来如预期,对应于ex.Message
:
提供了无效的请求URI。请求URI必须是必须设置绝对URI或BaseAddress。
已编辑:我正在寻找相同"要么全有要么全无"功能的简化实现(能够在出现第一个错误时终止Task.WhenAll
过程中的整套Tasks
),而不使用CancellationToken
。根据@Stephen Cleary发布的富有洞察力的评论,没有任何过载的"快捷方式"选项,也没有比当前更好的解决方案(就简单性而言)。
没有提供这种内置功能的重载。
通常,CancellationTokenSource
对象的自动取消不在BCL中(超时便利方法除外,该方法基于计时器自动取消)。如果我大胆猜测的话,我会说BCL团队认为这类重载有太多不同的用例,所以它们对足够广泛的受众来说不够有用,无法内置。
相反,适当的解决方案是在任何一个任务出现故障时自己触发CTS,这就是您的代码已经在做的事情。