Practical .NET

Working with Exceptions Before the Error Handler Does

Normally, you don’t care about first-chance exceptions -- it's only when something becomes a second-chance exception that you start to pay attention. But when you do care about all the exceptions, here’s how to work with them both in Visual Studio and in your code.

If you keep an eye on your Output window when debugging, you’ve had some exposure to first-chance exceptions. A first-chance exception refers to the state when the runtime has caught a problem, prepared an exception object, but hasn’t yet looked for an error handler. When you’re debugging, you may see messages roll by about first-chance exceptions as parts of the .NET Framework run into problems and deal with them.

Normally, you don’t care. Your program doesn’t stop running because the runtime finds an error handler for the exception within the .NET Framework (that is, the problem code was wrapped in a Try…Catch block). If there’s no handler for that first-chance exception, then it becomes a second-chance exception and your application will terminate. First-chance exceptions can be treated the same way that many developers deal with compile-time warnings: Who cares? It's just "noise."

However, like that "clack-clack-clack" from behind your car’s dashboard that you’ve been ignoring, it’s sometimes useful to pay attention to those errors. Leveraging those errors in your own code can let you centralize error logging for your application, for example.

In Visual Studio
I have to admit that, when I started treating compile-time warnings the same way that I treated compile-time errors, I found that I started producing more reliable code. In the same way, if you have a thorny problem in your application that nothing seems to fix, it might be worthwhile to look for the first-chance exceptions that the runtime is handling when you debug your code.

To have the debugger stop on your first-chance exception, go to the Debug menu choice and, from the Windows menu, select Exception Settings. This will open a window with a treeview of several different exception categories. Checking the Common Language Runtime Exceptions will cause the debugger to stop on all first-chance exceptions, even if an error handler higher up in the process would’ve taken care of it (you can also pick and choose among the exceptions you want the debugger to stop on). When you get tired of seeing those exceptions, you can click the Restore button in the toolbar (the one that looks like a little checkbox) to return to the default settings.

In Code
You should, of course, wrap much of your code in a Try…Catch block to give you a chance to process any exceptions and prevent your application from grinding to a halt. However, catching errors means that you might never know about things that are going regularly wrong with your application. Ideally, you’d like to have a complete log of all the exceptions that your application raises, both caught and uncaught. This would allow you (should you ever have time) to analyze your application’s "exceptional" performance. Even if you never have the time to do an analysis, it’s possible that such a log might be helpful in tracking down a problem, which, of course, is when you will have time.

Normally, the way to handle error logging is to create (or buy or download) a logging tool and scatter calls to its methods through your application’s Catch blocks. Rather than do that, however, you can centralize processing of all the exceptions generated by your applications by setting up a handler to catch the first-chance exceptions thrown in your application.

To catch and log all the errors, you can wire up a method to AppDomain’s FirstChanceException event. This event will notify of you of every exception in your application, except for those that actually corrupt your process’s state (access violations, for example). But, then, the runtime shouldn’t be letting you do those things in any managed language like C# or Visual Basic, anyway.

Here’s what the code to wire up a method to that event looks like in Visual Basic:

AddHandler AppDomain.CurrentDomain.FirstChanceException, AddressOf HandleFCE

In C#, this code achieves the same result:

AppDomain.CurrentDomain.FirstChanceException += HandleFCE;

The method that you tie to this event looks like any other event handler but requires the second parameter to be of the type FirstChanceExceptionEventArgs. That parameter has an Exception property that holds the Exception object that the runtime just created.

Here’s an example of what you might do in the event handler to log the problem (I’ve assumed the existence of a Utility class with a Log object):

Sub HandleFCE(source As Object, fce As FirstChanceExceptionEventArgs)

  Utility.Log.Write(String.Format("{0} exception event raised in {1}: {2}",
                                   fce.Exception.GetBaseException.GetType().Name,
                                   fce.Exception.TargetSite.Name,
                                   fce.Exception.Message)
End Sub

Of course, you can do it in one statement by using a lamba expression. In Visual Basic, wiring up that lambda expression looks like this:

AddHandler AppDomain.CurrentDomain.FirstChanceException, Sub(o, fce)
                                                                    Utiliity.Log.Write(…
                                                         End Sub

In C#, the code looks like this:

AppDomain.CurrentDomain.FirstChanceException += (o, fce) => { Utility.Log.Write(…); };

Handling this event doesn’t prevent the runtime from continuing to look for an error handler or to "bubble up" the Exception through the calling stack. You’re just being told about the error, you’re not being given a chance to handle it.

One caveat: You don’t want to permit an unhandled exception in this code so you should enclose the whole thing in a Try…Catch block. You also don’t want to throw an exception in the Catch or Finally of your error handler. If you do throw an exception in this method, it will be caught by the FirstChanceException event, reinvoking your first-chance exception handler. That could, eventually, lead to a stack overflow exception and…well, let’s just not think about that.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

  • Compare New GitHub Copilot Free Plan for Visual Studio/VS Code to Paid Plans

    The free plan restricts the number of completions, chat requests and access to AI models, being suitable for occasional users and small projects.

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

Subscribe on YouTube