In previous posts we talked about how use the Task object, async / await keywords and how to cancel a running task. In this last post I want to talk about another important point regarding task management: exception handling.
We will resume the example program created in the first post, which you can download here.
Let’s add a new button to the main form. We will call it “Start task with exception”.
We will also add an asynchronous method called “LongTaskWithExceptionAsync” and an event handler for the click event on the new button. Here is the code:
private Task<int> LongTaskWithExceptionAsync()
{
Task<int> T1 = new Task<int>(() =>
{
System.Diagnostics.Trace.WriteLine("BtnStartTaskWithException_Click->Task 1->Thread ID: " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
System.Threading.Thread.Sleep(5000);
int a = 1, b = 1;
if (a == b)
throw new ApplicationException("This is an exception!");
// Return a 'random' value
return DateTime.Now.Second;
});
T1.Start();
return T1;
}
private async void BtnStartTaskWithException_Click(object sender, EventArgs e)
{
System.Diagnostics.Trace.WriteLine("BtnStartTaskWithException_Click->Thread ID: " +
System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
try
{
int Val = await LongTaskWithExceptionAsync();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
As you can see, the call to LongTaskWithExceptionAsync is encapsulated in a try / catch block and the exception thrown is correctly caught. This also happens when you call, for example, the Wait method or the Result property of the Task object, but with a difference…
If you use the Wait method or the Result property, the exception is encapsulated in an AggregateExceptions object, and so you have to catch this kind of exception object. So add another button named “Start task with aggregate exception”:
And add this click event handler:
private void BtnStartTaskWithAggrException_Click(object sender, EventArgs e)
{
try
{
Task<int> T = LongTaskWithExceptionAsync();
T.Wait();
}
catch (AggregateException ex)
{
foreach (Exception inner_ex in ex.InnerExceptions)
{
if (inner_ex is ApplicationException)
{
MessageBox.Show(inner_ex.ToString());
}
else
{
throw;
}
}
}
}
The AggregateException object doesn’t seem to make much sense for a single task and a single exception, but it makes sense if you use, for example, the Task.WaitAll method… but this is another story… 😉
That’s all for now, see you soon to talk about other topics!