December 12, 2019

Custom Exception throws as Aggregate Exception

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.

References:

December 11, 2019

Setup Swagger with .Net Core Web API

Swagger is a open-source framework for describing your API using a common language that everyone can understand, usually in json or yaml formats which could be readable for both humans and machines. Swagger makes it easire for developers to design, build, document, and consume RESTful web services.

It provides the following benefits:

  • Human and machine readable.
  • Easier to understand for less technnical people. Developers and non-developers i.e. product managers and even potential clients can have a better perspective of the design of your API.
  • Adoptable for new changes, because it reflects the changes immediately on your swagger UI without writing special code for swagger. You only make changes to your REST API and swagger will do its part on its own.

Here is how you can implement swagger in .Net Core API project.

  • First you have to install two Nuget paackages.

    • Swashbuckle.AspNetCore
    • Swashbuckle.AspNetCore.Annotations
  • Once you have installed Nuget Packages, then inside ConfigureServices() method in Startup.cs, add this section:

     services.AddSwaggerGen(c =>
     {
      c.OperationFilter();
      c.EnableAnnotations();
      c.SwaggerDoc("v1", new Info
      {
       Title = "My API",
       Version = "v1"
      });
     });
      
  • Inside Configure() method in Startup.cs, we have to tell IApplicationBuilder object to use Swagger:

     app.UseSwagger();
      app.UseSwaggerUI(c =>
      {
       c.SwaggerEndpoint("/swagger/v1/swagger.json", "Sample API");
      });
      

When you run the .Net Core API project, go to the link, adding /swagger/index.html for your base URL. For example:

https://localhost:44319/swagger/index.html

It will display the swagger UI page similar to this.