There are occasions where you are aware of many exceptions within your code that you want to raise together in one go. Perhaps your system makes a service call to a middleware orchestration component that potentially returns many exceptions detailed in its response, or another scenario might be a batch processing task dealing with many items in one process that require you to collate all exceptions until the end and then throw them together.
Let us look at the batch scenario in more detail. In this situation, if you raised the first exception that you found it would exit the method without processing the remaining items. Alternatively, you could store the exception information in a variable of some sort and once all the elements are processed using the information to construct an exception and throw it. While this approach works, there are some drawbacks. There is the extra effort required to create a viable storage container to hold the exception information, and this may mean modifying existing code not to throw an exception but instead to log the details in this new ‘exception detail helper class’. This solution also lacks the additional benefits you get with creating an exception then, for example, the numerous intrinsic properties that exist within Exception objects that provide valuable additional context information to support the message within the exception. Even when all the relevant information has been collated into a single exception class, then you are still left with one exception holding all that information when you may need to handle the exceptions individually and pass them off to existing error handling frameworks which rely on a type deriving from Exception.
Luckily included in .Net Framework 4.0 is the simple but very useful AggregateException class which lives in the System namespace (within mscorlib.dll). It was created to use the Task Parallel Library, and its use within that library is described on MSDN here. Don’t think that is it’s only used though, as it can be put to good use within your code in situations like those described above where you need to throw many exceptions, so let’s see what it offers.
The AggregateException class is an exception type, inheriting from System.Exception, that acts a wrapper for a collection of child exceptions. Within your code, you can create instances of any exception based type and add them to the AggregateException’s collection. The idea is a simple one, but the AggregateException’s beauty comes in the implementation of this simplicity. As it is a regular exception class, it can handle in the usual way by existing code but also as a unique exception collection by the particular system that cares about all the exceptions nested within its bowels.
The class accepts the child exceptions on one of its seven constructors and then exposes them through its InnerExceptions property. Unfortunately, this is a read-only collection, and so it is not possible to add inner exceptions to the AggregateException after it has instantiated (which would have been nice) and so you will need to store your exceptions in a collection until you’re ready to create the Aggregate and throw it:
// create a collection container to hold exceptions
List<Exception> exceptions =
new
List<Exception>();
// do some stuff here ........
// we have an exception with an innerexception, so add it to the list
exceptions.Add(
new
TimeoutException(
"It timed out"
,
new
ArgumentException(
"ID missing"
)));
// do more stuff .....
// Another exception, add to list
exceptions.Add(
new
NotImplementedException(
"Somethings not implemented"
));
// all done, now create the AggregateException and throw it
AggregateException aggEx =
new
AggregateException(exceptions);
throw
aggEx;
The method you use to store the exceptions is up to you as long as you have them all ready at the time you create the AggregateException class. Seven constructors are allowing you to pass combinations of nothing, a string message, collections or arrays of inner exceptions.
Once created you interact with the class as you would any other exception type:
try
{
// do task
}
catch
(AggregateException ex)
{
// handle it
}
The key as it means that you can make use of existing code and patterns for handling exceptions within your (or third parties) codebase.
In addition to the general Exception members, the class exposes a few custom ones. The common InnerException property is there for compatibility, and this appears to return the first exception added to the AggregateException class via the constructor, so in the example above it would be the TimeoutException instance. All of the child exceptions expose via the InnerExceptions read-only collection property (as shown below).
The Flatten() method is another custom property that might prove useful if you find the need to nest Exceptions as inner exceptions within several AggregateExceptions. The method will iterate the InnerExceptions collection, and if it finds AggregateExceptions nested as InnerExceptions, it will promote their child exceptions to the parent level. As you can see in this example:
AggregateException aggExInner = new AggregateException("inner AggEx", new TimeoutException()); AggregateException aggExOuter1 = new AggregateException("outer 1 AggEx", aggExInner); AggregateException aggExOuter2 = new AggregateException("outer 2 AggEx", new ArgumentException()); AggregateException aggExMaster = new AggregateException(aggExOuter1, aggExOuter2);
If we create this structure above of AggregrateExceptions with inner exceptions of TimeoutException and ArgumentException then the InnerExceptions property of the parent AggregateException (i.e. aggExMaster) shows, as expected, two objects, both being of type AggregrateException and both containing child exceptions of their own:
But if we call Flatten()…
AggregateException aggExFlatterX = aggExMaster.Flatten();
…we get a new ArgumentException instance returned that contains still two objects, but this time the AggregrateException objects have gone, and we have the two child exceptions of TimeoutException and ArgumentException:
A useful feature to discard the AggregateException containers (which are effectively just packaging) and expose the real meat, i.e. the real exceptions that have been thrown and needs to be addressed.
If you’re wondering how the ToString() is implemented then the aggExMaster object in the examples above (without flattening) produces this:
System.AggregateException: One or more errors occurred. ---> System.AggregateException : outer 1 AggEx ---> System.AggregateException: inner AggEx ---> System.TimeoutException: The operation has timed out. --- End of inner exception stack trace --- --- End of inner exception stack trace --- --- End of inner exception stack trace ------> (Inner Exception #0) System.AggregateException: outer 1 AggEx ---> System.AggregateException: inner AggEx ---> System.TimeoutException: The operation has timed out. --- End of inner exception stack trace --- --- End of inner exception stack trace ------> (Inner Exception #0) System.AggregateException: inner AggEx ---> System.TimeoutException: The operation has timed out. --- End of inner exception stack trace ------> (Inner Exception #0) System.TimeoutException: The operation has timed out.<---<---<------> (Inner Exception #1) System.AggregateException : outer 2 AggEx --- System.ArgumentException: Value does not fall within the expected range. --- End of inner exception stack trace ------> (Inner Exception #0) System.ArgumentException: Value does not fall within the expected range.
As you can see the data has been formatted in a neat and convenient way for readability, with separators between the inner exceptions.
In summary, this is a very useful class to be aware of and have in your arsenal whether you are dealing with the Parallel Tasks Library or you just need to manage multiple exceptions. I like simple and neat solutions, and to me, this is a good example of that philosophy.