Stackify is now BMC. Read theBlog

What is an Unhandled Exception and How to Find Them

By: HitSubscribe
  |  June 7, 2024
What is an Unhandled Exception and How to Find Them

In the world of programming, exceptions are inevitable. They represent unexpected or exceptional events that can occur during the execution of a program. While some exceptions might be anticipated and handled gracefully, others might be unexpected, leading to application crashes or unexpected behavior. This guide delves into the nuances of exceptions in C#, focusing on the importance of handling an unhandled exception and the tools available for the same.

When the application code does not handle these errors properly, we term it as an "unhandled exception.

What is an Exception?

An exception represents a runtime error or an unexpected event that can occur during the execution of a program. In C#, an exception is a known type of error. When the application code does not handle these errors properly, we term it as an “unhandled exception.”

For instance, consider a scenario where you attempt to open a file on your disk, but the file doesn’t exist. In such cases, the .NET Framework will throw a FileNotFoundException. This situation exemplifies a foreseeable problem that can be addressed within the code.

What is an Unhandled Exception?

An unhandled exception arises when developers fail to anticipate or handle potential exceptions. Look at the code sample below. Here, the developer presumes that a valid file path will be provided in “args.” The code then proceeds to load the file’s contents. If no file path is given or if the specified file is missing, the code will throw exceptions, leading to unhandled exceptions.

static void Main(string[] args)
{
    string fileContents = File.ReadAllText(args[0]);

    //do something with the file contents
}

This code can easily throw several types of exceptions and lacks exception handling best practices. Here are some of the most common best practices to follow.

Best Practices for Exception Handling in C#

a. Use Specific Exceptions: Instead of using the general `Exception` class, it’s better to catch more specific exceptions. This allows for more precise error handling and debugging.

b. Avoid Catching Exceptions You Can’t Handle: If you can’t resolve an exception, it’s often better to let it propagate up the call stack to a level where it can be adequately addressed.

c. Use `finally` Blocks for Cleanup: The `finally` block ensures that resources get released, regardless of whether an exception occurs.

d. Don’t Rethrow Exceptions Incorrectly: Use `throw;` instead of `throw ex;` to preserve the original exception stack trace.

e. Log Exceptions: Always log exceptions for future analysis. This can be invaluable for debugging and identifying recurring issues.

You can find a more in-depth exploration on C# Exception best practices in this article.

Why Do We Need to Handle Exceptions?

Exception handling is crucial for several reasons:

  1. User Experience: Unhandled exceptions can lead to application crashes, affecting the user experience. A gracefully handled exception can provide informative feedback to the user rather than abruptly terminating the program.
  2. Data Integrity: Exceptions can occur during data processing or transactions. Failing to handle such exceptions can lead to data corruption or loss.
  3. Debugging and Maintenance: Proper exception handling can provide detailed error logs, making it easier for developers to debug and maintain the application.
  4. Resource Management: Unhandled exceptions can lead to resource leaks, such as open database connections or file handles that never get closed.
  5. Security: Revealing detailed error information, especially in web applications, can expose vulnerabilities. Proper exception handling can prevent exposing sensitive information.

Types of Unhandled Exceptions in C#

In C#, there are several exceptions that, if not handled, can lead to significant issues in applications. Some of the common unhandled exceptions include:

  • FileNotFoundException: Triggered when trying to access a file that doesn’t exist.
  • NullReferenceException: Occurs when attempting to use an object reference that is null.
  • IndexOutOfRangeException: Thrown when trying to access an array or collection with an index that’s out of its bounds.
  • DivideByZeroException: Arises when there’s an attempt to divide by zero.
  • InvalidOperationException: Occurs when a method call is invalid for the object’s current state.

This is just a small subset of potential unhandled exceptions. Developers must be vigilant and incorporate robust exception handling mechanisms to catch and handle such scenarios.

How to Catch Unhandled Exceptions in C#

The .NET Framework offers events that catch unhandled exceptions. Register for these events once when your application starts. In ASP.NET, use the Startup class or Global.asax. For Windows applications, insert the registration in the first few lines of the Main() method.

static void Main(string[] args)
{
  Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
  AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

  string fileContents = File.ReadAllText(args[0]);
  //do something with the file contents
}

static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
  // Log the exception, display it, etc
  Debug.WriteLine(e.Exception.Message);
}

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
  // Log the exception, display it, etc
  Debug.WriteLine((e.ExceptionObject as Exception).Message);
}

MORE: AppDomain.UnhandledException Event (MSDN)

View Unhandled Exceptions in Windows Event Viewer

If your application encounters unhandled exceptions, the Windows Event Viewer may log them under the “Application” category. This feature assists developers in diagnosing sudden application crashes.

The Windows Event Viewer might log two entries for the same exception: one as a .NET Runtime error and another as a generic Windows Application Error.

The Windows Event Viewer might log two entries for the same exception: one as a .NET Runtime error and another as a generic Windows Application Error.

From the .NET Runtime:

Application: Log4netTutorial.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IndexOutOfRangeException
   at Log4netTutorial.Program.Main(System.String[])

Logged under Application Error:

Faulting application name: Log4netTutorial.exe, version: 1.0.0.0, time stamp: 0x58f0ea6b
Faulting module name: KERNELBASE.dll, version: 10.0.14393.953, time stamp: 0x58ba586d
Exception code: 0xe0434352
Fault offset: 0x000da882
Faulting process id: 0x4c94
Faulting application start time: 0x01d2b533b3d60c50
Faulting application path: C:\Users\matt\Documents\Visual Studio 2015\Projects\Log4netTutorial\bin\Debug\Log4netTutorial.exe
Faulting module path: C:\WINDOWS\System32\KERNELBASE.dll
Report Id: 86c5f5b9-9d0f-4fc4-a860-9457b90c2068
Faulting package full name: 
Faulting package-relative application ID: 

Also read-https://stackify.com/the-linq-join-operator-a-complete-tutorial/

Custom Exceptions in C#

Sometimes, the built-in exception types don’t cater to specific needs. In such cases, C# allows developers to define custom exceptions. Custom exceptions can provide more context or handle domain-specific errors.

To create a custom exception:
1. Derive from the `Exception` class.
2. Provide a public constructor to initialize the exception.
3. (Optional) Override the `ToString` method to customize the error message.

Starting with C# 6, exception filters allow developers to specify a condition with the `catch` clause

Exception Filters in C# 6 and Later

Starting with C# 6, exception filters allow developers to specify a condition with the `catch` clause. The catch block executes only if the condition evaluates to `true`.

Example:

try
{
    // Code that might throw exceptions
}
catch (MyException ex) when (ex.ErrorCode == 404)
{
    // Handle only if ErrorCode is 404
}

Performance Implications of Exceptions

While exceptions are a powerful tool for managing errors, they can impact performance if misused. It’s essential to understand that exception handling should not be a mechanism for regular control flow in your application. Throwing exceptions incurs a performance cost, so use them judiciously.

Handling Exceptions in Multithreaded and Asynchronous Code

With the rise of asynchronous programming, especially with `async` and `await` in C#, handling exceptions becomes a bit more nuanced. Exceptions thrown in an asynchronous method need to be caught in the calling method when the task is awaited.

Find Unhandled Exceptions with Retrace

Retrace boasts impressive error monitoring capabilities. It can automatically collect all .NET exceptions that your application encounters, including unhandled exceptions and all thrown exceptions or first-chance exceptions.

Improve Your Code with Retrace APM

Stackify's APM tools are used by thousands of .NET, Java, PHP, Node.js, Python, & Ruby developers all over the world.
Explore Retrace's product features to learn more.

Learn More

Want to contribute to the Stackify blog?

If you would like to be a guest contributor to the Stackify blog please reach out to [email protected]