I faced this issue while using Custom Exception class with Task Parallel Library. The issue was that when I throw the Custom Exception, it was not getting caught in Custom Exception catch clause. In this post I will explain how you can catch
Custom Exception when working with TPL.
Lets start with example code, here is the definition for my Custom Exception class.
class MyCustomException : Exception
{
//custom code...
}
Here is the function GetOrderCount() with is throwing this Custom Exception from new Task.
public static class UserManager
{
public static int GetOrderCount(string userName)
{
int orderCount = Task.Run(() => {
if (userName == "test") // any condition, to validate and throw exception...
{
throw new MyCustomException();
}
return 10; // get value from database...
}).Result;
return orderCount;
}
}
Here is the Controller's action method which is calling previous method GetOrderCount().
[HttpGet("{userName}")]
public IActionResult GetOrderCount(string userName)
{
try
{
int count = UserManager.GetOrderCount(userName);
return Ok(new { OrderCount = count });
}
catch (MyCustomException ex1) // this will get ignored
{
//handle for MyCustomException
}
catch (Exception ex3) // this will handle any exception, including MyCustomException
{
//handle for generic exception
}
}
Here is the issue, I was expecting to run code for MyCustomException handle but it was not getting there. After searching on this, I found that this is the behavior designed because of TPL.
If a child task throws an exception, that exception is wrapped in an AggregateException exception before it is propagated to the parent. And chain cycle continues if the parent itself is a child task of some other parent task, i.e. which also wraps its own AggregateException exception before it propagates it back to the calling thread.
In a nutshell, MyCustomException is actually wraps in AggregateException, so I have to place a catch for AggregateException instead of MyCustomException. And to get access MyCustomException object, I have to read the InnerException property of AggregateException.
Here is the updated code after making this change.
[HttpGet("{userName}")]
public IActionResult GetOrderCount(string userName)
{
try
{
int count = UserManager.GetOrderCount(userName);
return Ok(new { OrderCount = count });
}
catch (AggregateException ex1) // now this will handle MyCustomException
{
MyCustomException myException = ex1.InnerException as MyCustomException;
//other handling logic for MyCustomException...
}
catch (Exception ex3) // this will handle any other exception
{
//handle for generic exception
}
}
This way you can get handle of your Custom Exception.
