Handling task exceptions using try/catch block

Let's face it; sometimes things just go wrong with our code. Even with the simplified parallel programming model provided by the TPL, we still need to be able to handle our exceptions.

Tasks use System.AggregateException to consolidate multiple failures into a single exception object. In this recipe, we will take a look at the simplest way to handle System.AggregateException in our tasks: the try/catch blocks.

The try-catch statement consists of a try block followed by one of more catch blocks, which specify handlers for different exceptions. The try block contains the guarded code that may cause the exception.

Getting ready…

For this recipe we need to turn off the Visual Studio 2012 Exception Assistant. The Exception Assistant appears whenever a runtime exception is thrown, and intercepts the exception before it gets to our handler.

  1. To turn off the Exception Assistant, go to the Debug menu and select Exceptions.
  2. Uncheck the user-unhandled checkbox next to Common Language Runtime Exceptions.
    Getting ready…

How to do it…

Let's return to our WordCount solution so we can see how to handle an AggregateException thrown by a parallel task.

  1. Start a new project using the C# Console Application project template and assign WordCount6 as the Solution name.
  2. Add the following using statements are at the top of your Program class:
    using System;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
  3. For this recipe, we will just need a single task. The task will be very similar to our other word count tasks, but in this one we will simulate a problem with the System.Net.WebClient by creating and throwing a System.Net.WebException. In the Main method of your Program class, create System.Task that looks as the following Task:
    Task<int> task1 = Task.Factory.StartNew(() =>
    {
        const string headerText = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)";
        Console.WriteLine("Starting the task.");
        var client = new WebClient();
        client.Headers.Add("user-agent", headerText);
        var words = client.DownloadString(@"http://www.gutenberg.org/files/2009/2009.txt");
        var ex = new WebException("Unable to download book contents");
        throw ex;
        return 0;
    });
  4. Just below the Task, let's put in our try/catch blocks as shown in the following code snippet. In the catch block, we will want to specifically catch System.AggregateException.
    try
    {
    }
    catch (AggregateException aggEx)
    { 
    }
  5. Now let's implement the body of our try block. The body of the try block should be as shown in the following code snippet. There are a couple of subtle but important concepts in here that will be explained later in the chapter.
    try
    {
        task1.Wait();
        if (!task1.IsFaulted)
        {
         Console.WriteLine("Task complete. Origin of Species word count: {0}",task1.Result);
        }
    }
  6. Next, let's implement the body of our catch block. It should look as shown in the following code snippet:
    catch (AggregateException aggEx)
    {
        foreach (var ex in aggEx.InnerExceptions)
        {
          Console.WriteLine("Caught exception: {0}", ex.Message);
        }
    }
  7. After the catch block, let's finish up by prompting the user to exit, and waiting on the user to hit Enter.
    Console.WriteLine("Press <Enter> to exit.");
    Console.ReadLine();
  8. In Visual Studio 2012, press F5 to run the project. You should see output as shown in the following screenshot:
    How to do it…

How it works…

All of this stuff has been pretty self-explanatory so far, but handling exceptions in task involves a couple of subtleties that need to be pointed out.

The task itself is pretty straightforward. Other than throwing the System.Net.WebException, there is nothing out of the ordinary here.

Let's take a closer look at the try/catch blocks. The first statement in the try block System.Threading.Task.Wait() to wait on task completion. However, there is another purpose here. Unhandled exceptions thrown inside a task are swallowed by the runtime and wrapped up in System.AggregateException. It is your job to handle this.

The TPL also has the concept of AggregateException being observed. If AggregateException is raised by your task, it will only be handled if it is currently being observed. This is very important to understand. If you never take an action that causes the exceptions to be observed, you are going to have a problem. When the Task object is garbage collected, the Finalize method of the task will see that the task had unobserved exceptions, and it will throwSystem.AggregateException. You will not be able to catch an exception thrown by the finalizer thread and your process will be terminated.

So how to you observe an AggregateException, you ask? The Systm.Threading.Task class has a few methods and properties call triggers that cause System.AggregateException to be observed. A few of these are as follows:

  • Task.Wait
  • Task.WaitAny
  • Task.WaitAll
  • Task.Result

Using any of these trigger methods indicates to the runtime that you are interested in observing any System.AggregateException that occurs. If you do not use one of the trigger methods on the Task class, the TPL will not raise any AggregateException, and an unhandled exception will occur.

Now, let's take a look at the catch block. System.AggregateException can wrap many individual exception objects. In our catch block, we need to loop through AggregateException.InnerExceptions to take a look at all of the individual exceptions that occurred in a task.

It is important to note that there is really no way to correlate an exception from the AggregateExcetion.InnerExceptions collection back to the particular task that threw an exception. All you really know is that some operation threw an Exception.

System.AggregateException overrides the GetBaseException method of exception, and returns the innermost exception, which is the initial cause of the problem.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.43.122