Centralized Exception handling in .NET Windows Forms Applications

There is an easy way, in .NET, to centralize the treatment of all unexpected errors.

First of all, instead of launching the application directly in a Form, you need first to write a Sub called Main, in a module. Then, set the Startup Object to that Sub in the Application tab of the project's Properties Window (last entry in the Project menu). You must make sure that Enable application framework is unchecked for this to work, because what that does is simply write a Sub Main for you, and you cannot have two of these in the same application.

Professional programmers use that approach for most applications, because it enables them to check the environment and set things up before loading the main Form. It also enables you to launch the application in different ways on in different Forms, depending on the situation, command line arguments or the user.

But over all, it enables you to trap Exception events at the application level. Here is the basic code for that module.
Module Module1
                       Public Sub Main()
                          AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf UnhandledExceptionHandler
                          AddHandler Application.ThreadException, AddressOf ThreadExceptionHandler
                          Application.Run(New Form1)
                       End Sub
                       Private Sub UnhandledExceptionHandler(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)
                          YourReportingMethod(CType(e.ExceptionObject, Exception))
                       End Sub
                       Private Sub ThreadExceptionHandler(ByVal sender As Object, ByVal e As Threading.ThreadExceptionEventArgs)
                       End Sub
                       Private Sub YourReportingMethod(e As Exception)
                       End Sub
                      End Module

Open in new window

The last method (you can give it any name you want) is your unexpected exception handler. Do whatever you want there. Log the exception in the event log, in a database or in a file. Report the exception in a mail message. Play some soothing music and apologize for your mistake. All of these.

You will end up in that routine anytime an Exception is triggered in code that is not inside of a Try...Catch block. Note that it receives the Exception as an argument, so you have all the necessary information needed to help you pinpoint what happened. If you install a Debug version of your application on your user's computer, the StackTrace will also pinpoint the exact line of code where the error occured. This can be useful when distribute your first few versions that always contain unexpected problems.

You can also make it a point, when you have a Try...Catch, to systematically call that routine whenever an unexpected Exception is triggered. You can do it with blocks that end like the following:
                         'Your code
                      Catch ex As SqlException
                         'SQL Exception handling
                      Catch ex As IO.EndOfStreamException
                         'Unexpected end of the file
                      Catch ex As IOException
                         'File Exception handling
                      End Try

Open in new window

The Catch...Throw at the end does the trick. It will send the Exception up the stack trace. If you terminate all your Try...Catch blocks that way, unhandled exceptions will always bubble up to your centralized error handling routine.

You will see some programmers Catch ex As Exception and Throw ex instead of a simple Catch/Throw. This works, but resets the StackTract to the line on which you call Throw ex. You won't be able to know what happened before the Throw, only the exception that was triggered. This is not very useful, so go for the Catch/Throw.

Some programmers do not like that approach, because the Exception that bubbles up could be trapped by another Try...Catch up the calls line. If this is your way of thinking, simply make your reporting method Public instead of Private as I did, Catch ex As Exception instead of simply Catch, and call your routine, passing it the ex that you catched.

This is a .NET technique, so it also works in C# and most languages supported for Windows Applications.

Comments (0)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.