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();