.NET Core - Handling Exceptions

What is an exception?

 
An exception is thrown when your code reaches a state that was not planned at the time of execution. It may happen mainly due to unexpected input or due to bad quality code.

Benefits of handling exceptions

 
Preventing your application from crashing is one of the various benefits of handling exceptions. Some others are as follows:
  • Present the end-user with a more detailed message about what happened;
  • Improve the security of your system, not displaying any sensitive data to your end-users;
  • Avoid crashes, leaving your clients upset;
  • Logging details about what caused the exception.

Why handle exceptions?

 
It is a software development good practice to prevent exceptions from being thrown to your end-users, but there are more reasons for this.
  • Create planned exception handlers, based on the exception type;
  • Have different process flows, keeping the data integrity;
  • More accurate logging;
  • Protect your code, not letting sensitive data to be exposed.

Exceptions hierarchy

 
The compiler is going to hit in the first exception handler which satisfies the exception thrown, so we must pay attention to the exception hierarchy and the exception handlers' order. Otherwise, we may have a result different than expected.
 
As every exception is derived from System.Exception, the default exception handler must be the last one so it is only going to be hit if none of the exception handlers satisfies the condition. 
Sample of exceptions
 
For the samples below, we are going to use a .NET Core Console Application.
 

Custom Exception

 
Creating the custom exception
 
This is a very basic custom exception handler. You may improve it as far as you wish. Note that it must inherit from the Exception.
  1. public class CustomException : Exception    
  2. {    
  3.     public CustomException(): base("This is a custom exception")    
  4.     {  
  5.     }    
  6. }  
Exception handler
  1. public static void CustomException() {  
  2.  try {  
  3.   throw new CustomException();  
  4.  } catch (CustomException ex) //must comes first    
  5.  {  
  6.   Console.WriteLine(ex.Message);  
  7.  } catch (Exception ex) {  
  8.   Console.WriteLine(ex.Message);  
  9.  }  
  10. }  
Note the exceptions' order, if you change their order, the order in which the first exception is going to hit will also change.
 
ArithmeticException
  1. int division = 0;  
  2.   
  3. try {  
  4.  var throwException = 15 / division;  
  5. catch (ArithmeticException ex) //must comes first    
  6. {  
  7.   
  8.  Console.WriteLine(ex.Message);  
  9. catch (Exception ex) {  
  10.   
  11.  Console.WriteLine(ex.Message);  
  12. }  
The above point applies to all the below-mentioned exception handlers too.
 
NullReferenceException
  1. List < int > nullIntegerList = null;  
  2. try {  
  3.  var throwException = nullIntegerList.Count;  
  4. catch (NullReferenceException ex) //must comes first    
  5. {  
  6.  Console.WriteLine(ex.Message);  
  7. catch (Exception ex) {  
  8.  Console.WriteLine(ex.Message);  
  9. }  
IndexOutOfRangeException
  1. int[] sampleArray = new int[3] {  
  2.  1,  
  3.  2,  
  4.  3  
  5. };  
  6. try {  
  7.  var throwException = sampleArray[3];  
  8. catch (IndexOutOfRangeException ex) //must comes first    
  9. {  
  10.  Console.WriteLine(ex.Message);  
  11. catch (Exception ex) {  
  12.  Console.WriteLine(ex.Message);  
  13. }  
FileNotFoundException
  1. try {  
  2.  var throwException = File.Open(@ "C:\notExistentFile.jpg", FileMode.Open);  
  3. catch (FileNotFoundException ex) //must comes first    
  4. {  
  5.  Console.WriteLine(ex.Message);  
  6. catch (Exception ex) {  
  7.  Console.WriteLine(ex.Message);  
  8. }  
Congratulations. You have seen a very important way to protect your code and also to have more accurate logging by handling exceptions by their type. 
External References