No matter how efficient your software application runs, one exception due to bad code can crash the application and make it unavailable for even millions of users. That is simply why exception handling is a critical requirement for any code. This article explains the best practices you should follow when handling exceptions in C#.
What is Exception Handling?
An exception is an error that occurs during the execution of a program that disrupts its normal control flow or execution. Examples include invalid user input, unavailable resources like files and folders, and trying to access elements of arrays in a non-existent index. Exception handling is handling possible error conditions to allow the program to continue without disruption.
What are the best practices for exception handling in C#?
C# provides several ways to handle exceptions like try-catch-blocks, multiple try-catch-blocks, and user-defined custom exceptions. Here are some best practices you should follow for you to build a well-designed application.
1. If you can handle the error, do not throw exceptions
There can be error conditions that are very common or likely to occur in many applications. For example, suppose you have a division operation in your code. The 'divide by zero' is a common exception for such operations.
int num1 = 100;
int num2 = 0;
try {
Console.WriteLine(num1 / num2);
}
catch (DivideByZeroException) {
Console.WriteLine("Divide by zero exception occured .");
}
But, you do not have to throw exceptions for such common errors in the first place. Simply check if the numbers contain 0 so you can set it to a non-zero default value.
int num1 = 100;
int num2 = 0;
if (num2 == 0) {
num2 = 1; //setting a default value
}
Another example is the "NullReferenceException," which can occur if an object or a variable becomes null. Instead of throwing an exception, check if the object or variable is null before doing any operation. Here is how you can do it in C#,
User user = null;
var name = user?.Name;
Appending the '?' symbol C# automatically checks that the object is null.
2. Logging exceptions
Logging is very important in exception handling with any programming language. As a best practice, ensure you log the exception object without just logging an error message. The exception object has a lot of information, including stack trace and exception type, which are crucial to troubleshooting the issue. Also, do not forget to provide a meaningful and grammatically correct error message for you to make the troubleshooting hassle-free
try {
//divide by zero
}
catch (DivideByZeroException exception)
{
Logger.LogError(exception, "Divide By Zero Exception");
}
Using ClearInsights Exception Handling is an easy way to log exceptions and automatically push the exception into your backlog to work on. Email notifications will also be sent out to team members based on configured settings. Create a free ClearInsights account to try.
Integrate ClearInsights Logging with the code below
builder.Logging.AddClearInsightsLogger(configuration =>
{
configuration.ApiKey = "{ApiKey}";
configuration.Secret = "{Environment Client Secret}";
configuration.ApplicationName = "{Application Name}";
});
However, you do not need to log every exception manually like this. You can make logging even more informative and advanced if you have an automated way to log exceptions. Logging tools help you to achieve that. ClearInsights centralized logging, for example, is a simple but intuitive logging tool that you can integrate into your application for automatic logging.
Using this tool, you can record not only the exception message but also other information like the product, environment, source, and stack trace of each log. You can also get logging reports to see an overview of the different log types like Critical, error, warning, informational, and trace that provide different levels of logs. Another best thing about using this tool is you can filter them to get insight into the exceptions that frequently occur in your system. Thus, as a best practice, ensure that you use a good logging tool that provides you with an easy application logging experience.
3. Use throw statements to preserve the stack trace
In some C# applications, developers use the "throw ex" statement instead of the " throw " statement in exceptions. This will not be helpful if you want to get the complete stack trace from the beginning. Because the "throw ex" statement does not keep the stack traces so that it is difficult to track down where the error first occurred. But the "throw" statement does log the stack trace. Thus, do not forget to use the throw statement as follows instead of using the 'throw ex' statement in exceptions for better exception handling.
catch(Exception ex)
{
throw;
}
4. Create custom exceptions using the Exception keyword
Create custom exceptions to provide explicit exception handling for your application. Use the "Exception" keyword like in the following example when you declare one.
public class MyCustomException: Exception{}
You can define your own exception handling behavior and exceptions common across your application classes using custom exceptions. Also, it is a good practice to include three common constructors for custom exception classes, which are: Exception(), which sets the default values; exception (String) which you can pass a message; and Exception(String, Exception), for setting an inner exception. When you define the custom exception, do not forget to include logging for every exception you declare there. In addition, use additional properties to provide additional information about the exception.
5. Use already existing exceptions as much as possible
The fifth best practice of C# exception handling is using the pre-defined exceptions whenever possible in your code. This can be quite contradictive to the 4th best practice. But creating custom exceptions is best if your application code has more specific error cases. Following are some of the predefined exceptions available in C# and when they are used:
- FileNotFoundException - Throws when the program cannot locate a file.
- DivideByZeroException - Divide a number by Zero
- ArgumentNullException - When an argument value is null
- InvalidOperationException - When an operation is invalid. For example, trying to close a connection that is already closed.
- ArrayIndexOutOfBoundException - When you try to access an element of an array that is at an index outside its maximum index.
Summary
From this article, you learned the following five best practices of exception handling in C#.
- Handling common errors rather than throwing exceptions
- Using already existing exceptions as much as possible
- Using custom exceptions
- Using application logging
- Using throw statements
One of the most important practices is logging your exceptions to better support the troubleshooting process.
ClearInsights is the perfect logging and monitoring tool provider for C# applications. Integrate ClearInsights tools into your application and make debugging your application an easy process.
Top comments (0)