C# WPF应用程序中的第一个异常导致多个Task.Whell终止
下面的示例代码片段通过使用C# WPF应用程序中的第一个异常导致多个Task.Whell终止,c#,wpf,multithreading,asynchronous,async-await,C#,Wpf,Multithreading,Asynchronous,Async Await,下面的示例代码片段通过使用async/await编码技术(类似于MSDN演示示例:)读取/处理Web Url示例列表列表Url的内容来实现多任务功能。出于测试目的,Url列表Url包含两个错误项 清单1。多任务WPF异步/等待实现中的错误处理 输出文本看起来与预期一致,对应于ex.Message: 提供了无效的请求URI。请求URI必须是 必须设置绝对URI或基地址 已编辑:我正在寻找相同“全部或无”功能的简化实现(允许在任务中终止整个任务集。当出现第一个错误时终止所有过程),而无需使用取消令牌
async/await
编码技术(类似于MSDN演示示例:)读取/处理Web Url示例列表列表Url
的内容来实现多任务功能。出于测试目的,Url列表Url
包含两个错误项
清单1。多任务WPF异步/等待实现中的错误处理
输出文本看起来与预期一致,对应于ex.Message
:
提供了无效的请求URI。请求URI必须是
必须设置绝对URI或基地址
已编辑:我正在寻找相同“全部或无”功能的简化实现(允许在
任务中终止整个任务集
。当出现第一个错误时终止所有过程),而无需使用取消令牌
。根据@Stephen Cleary发表的深刻评论,没有任何重载“快捷方式”选项,也没有比当前解决方案更好的解决方案(就简单性而言)。没有重载提供这种内置功能
通常,BCL中没有自动取消CancellationTokenSource
对象(超时便利方法除外,该方法基于计时器自动取消)。如果我冒昧地猜测一下,我会说BCL团队觉得这些类型的重载有太多不同的用例,因此它们对于足够广泛的受众来说没有足够的用处,无法内置
相反,适当的解决方案是在任何一个任务出现故障时自己触发CTS,这是您的代码已经在做的事情。没有提供这种内置功能的重载
通常,BCL中没有自动取消CancellationTokenSource
对象(超时便利方法除外,该方法基于计时器自动取消)。如果我冒昧地猜测一下,我会说BCL团队觉得这些类型的重载有太多不同的用例,因此它们对于足够广泛的受众来说没有足够的用处,无法内置
相反,适当的解决方案是在任何一个任务出现故障时自己触发CTS,这是您的代码已经在做的事情。问“是否可能”的问题几乎没有用处。这是软件。您总是可以编写代码来完成您可以想象的事情。这只是一个你想付出多少努力的问题。实现目标总是有很多不同的方法。在我看来,您的代码是有效的,事实上,它使用CTS的方式与预期的一样。你有什么具体的问题要解决吗?使用CTS是否会干扰程序的正确运行?如果您想要答案,请缩小问题的范围。@PeterDuniho我已经非常清楚地表明,目的是通过消除CancellationToken来简化代码。这不仅仅是取决于时间/工作量的某种“抽象可能性”,因为所需的(简化的)解决方案可能不存在。CancellationToken对于这种商业逻辑来说似乎是一种过度的杀伤力;如果异常处理程序可以在没有令牌的情况下终止任务,那么就可以了。感谢和问候,@AlexBell没有过载或任何提供捷径的东西;您已经拥有的代码是最好的方法。@StephenCleary非常感谢您对这个问题的研究和您富有洞察力的评论:现在情况已经清楚了。你可以把它作为答案贴出来,我会接受的。最好的问候,问“可能吗”的问题几乎从来没有用过。这是软件。您总是可以编写代码来完成您可以想象的事情。这只是一个你想付出多少努力的问题。实现目标总是有很多不同的方法。在我看来,您的代码是有效的,事实上,它使用CTS的方式与预期的一样。你有什么具体的问题要解决吗?使用CTS是否会干扰程序的正确运行?如果您想要答案,请缩小问题的范围。@PeterDuniho我已经非常清楚地表明,目的是通过消除CancellationToken来简化代码。这不仅仅是取决于时间/工作量的某种“抽象可能性”,因为所需的(简化的)解决方案可能不存在。CancellationToken对于这种商业逻辑来说似乎是一种过度的杀伤力;如果异常处理程序可以在没有令牌的情况下终止任务,那么就可以了。感谢和问候,@AlexBell没有过载或任何提供捷径的东西;您已经拥有的代码是最好的方法。@StephenCleary非常感谢您对这个问题的研究和您富有洞察力的评论:现在情况已经清楚了。你可以把它作为答案贴出来,我会接受的。顺致敬意,
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.
if (cts != null) cts.Cancel();