Consider the following code:
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
static class Program
{
static void Main()
{
var tasks = new Task[1];
tasks[0] = Task.Run(() => throwExceptionAfterOneSecond())
.ContinueWith(task => {
Console.WriteLine("ContinueWith()"); }, TaskContinuationOptions.NotOnFaulted);
try
{
Task.WaitAll(tasks);
}
catch (AggregateException ex)
{
Console.WriteLine("Exception received: " + ex.InnerExceptions.Single().Message);
}
}
static void throwExceptionAfterOneSecond()
{
Thread.Sleep(1000);
throw new InvalidOperationException("TEST");
}
}
}
This gives the following result:
Exception received: A task was canceled.
My question is simple: how do I get the source InvalidOperationException("TEST");, not System.Threading.Tasks.TaskCanceledException?
Please note that if you delete the part .ContinueWith(), this works as I expected, and the output in this case Exception received: TEST.
(Also note that in this example .Net 4.5 is used, but the source code must use .Net 4.0)
Decision
Thanks to the answers, now it works. I chose the following solution: I had to wait for both the original task and the continuation task:
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
static class Program
{
static void Main()
{
var tasks = new Task[2];
tasks[0] = Task.Run(() => throwExceptionAfterOneSecond());
tasks[1] = tasks[0].ContinueWith(task => {
if (task.Status == TaskStatus.RanToCompletion)
Console.WriteLine("ContinueWith()"); });
try
{
Task.WaitAll(tasks);
}
catch (AggregateException ex)
{
Console.WriteLine("Exception received: " + ex.InnerExceptions.Single().Message);
}
Console.WriteLine("Done.");
}
static void throwExceptionAfterOneSecond()
{
Thread.Sleep(1000);
throw new InvalidOperationException("TEST");
}
}
}
source
share