User Input

Central Exception Handlers

It's tedious to add exception handling to all procedures in a project, but it's a necessity. Every unexpected exception must be displayed to the user in the same format, and this can take a considerable amount of code. Adding a central exception handler can help tremendously.

A central exception handler is a procedure that you call when an exception occurs. At a minimum, a central exception handler displays a consistent error message to the user. However, you can add capabilities to the central exception handler as you see fit. For instance, you can have your central exception handler send an e-mail message to a support specialist whenever an unexpected exception occurs, or you can actually include code to take a snapshot of the state of the machine and log the loaded applications and loaded DLLs along with their versions.

The following is a typical central exception handler:

 Friend Sub HandleException(ByVal strModule As StringByVal As Exception)    ' Purpose   :  Provide a central exception-handling mechanism.    ' Accepts   :  strModule - the module in which the error was    '                 encountered (form, class, standard, and so on.)    '              e - the exception that occurred.     Dim strMessage As String    Dim strCaption As String    Try        ' Build the error message.          strMessage = "Exception: " & e.Message & ControlChars.CrLf & _                    ControlChars.CrLf & _                    "Module: " & strModule & ControlChars.CrLf & _                    "Method: " & e.TargetSite.Name & ControlChars.CrLf & _                    ControlChars.CrLf & _                    "Please notify My Software's tech support " & _                    "at 555-1213 about this issue." & ControlChars.CrLf & _                    "Please provide the support technician with " & _                    "information shown in " & ControlChars.CrLf & _                    "this dialog box as well as an explanation of what " & _                    "you were" & ControlChars.CrLf & "doing when this " & _                    "error occurred."       ' Build the title bar text for the message box. The text includes       ' the version number of the program.        With System.Reflection.Assembly.GetExecutingAssembly.GetName.Version          strCaption = "Unexpected Exception! Version: " & _                       .Major & "." & _                       .Minor & "." & _                       Format(.Revision, "0000")       End With        ' Show the error to the user.       MessageBox.Show(strMessage, strCaption, _                       MessageBoxButtons.OK, MessageBoxIcon.Exclamation)    Finally    End Try End Sub 

To use this central exception handler, you simply call the procedure in an exception handler like this:

Private Sub Button1_Click(ByVal sender As System.Object, _                           ByVal As System.EventArgs) _                           Handles Button1.Click    Dim intNumerator As Integer = 100    Dim intDenominator As Integer = 0    Dim lngResult As Long    Try        ' This next statement throws an exception.       lngResult = CLng(intNumerator / intDenominator)    Catch objE As Exception       Call HandleException(Me.Name, objE)    End Try End Sub 

When the exception illustrated in the previous example occurs, the central exception handler is called and it displays the dialog box shown in Figure 10-1. Imagine trying to display such a comprehensive error message from every exception handler in every procedure in every module without using a central exception handler!

Figure 10-1. A central exception handler makes it easy to display comprehensive error messages.

graphics/f10ln01.jpg

Notice the use of Me.Name in the call to the exception handler, which makes the line of code a bit more portable. You can copy the Catch statement as well as this statement to the Clipboard and paste it into other procedures. This enables you to write the exception handlers in your various procedures more quickly and allows you to change the way exceptions are handled or displayed by changing code in one location rather than in hundreds or thousands of locations.

The Exception object tracks the procedure in which an exception occurs (e.TargetSite.Name), but it doesn't keep track of the object (module) involved. This is why the reference to Me.Name is in the code shown previously.

For modules other than forms, Name doesn't work, so you have to use the literal class name. However, in this situation it's best to create a module-level constant and use the constant so that you don't have to modify the exception handlers' code if a module's name is changed. If you use a generic constant name (such as mc_Module), you can copy the Catch and Call HandleException statements from one module and paste them into another module without having to make any modifications.

Although the central exception handler shown earlier displays the error message to the user in a consistent fashion, you must determine the code that each exception handler will have in addition to calling the HandleException method. For instance, what additional code (if any) should go in the Catch block? What code should go in the Finally block? You should make your exception handlers as generic as possible, but you also should make sure that each one is appropriate for the procedure in which it resides.

Logging Exceptions to a Text File

It's often useful to have a log of any exceptions that occur. For instance, during the testing phase of your project, you need to know as much as you can about any errors that happen. You usually can't rely on reports from users. When it's critical that you know about every exception in your program, you should use a central exception handler to create an exception log.

Creating an exception log is simple. First create a central exception handler as discussed earlier. Then, within the central exception handler, devise a mechanism to log the exceptions to a text file. The following code illustrates one way to log exceptions to a text file. This code is shown as it would appear as part of the central exception handler shown previously. It assumes that there is a global variable in the project called g_strExceptionLogFileName that contains the path and name of the exception log file.

' Open a new stream writer to the log file. Dim objStream As New System.IO.StreamWriter(g_strExceptionLogFileName, _                                             True) Dim strLogText As String  ' Create the log text. strLogText = DateTime.Now & ControlChars.CrLf & _              "Exception: " & e.Message & ControlChars.CrLf & _              "Module: " & strModule & ControlChars.CrLf & _              "Method: " & e.TargetSite.Name & ControlChars.CrLf & _              "Stack: " & e.StackTrace & ControlChars.CrLf ' Write the exception message. objStream.WriteLine(strLogText) ' Flush the text to the log file. objStream.Flush() ' Close the log file. objStream.Close() 

If the file does not exist, the StreamWriter creates it. If the file exists, text is appended to it. Once the file is opened, a log entry is written. Here is a sample of a text file created using the previous code:

4/8/2002 11:43:00 PM Exception: Arithmetic operation resulted in an overflow. Module: Form1 Method: Button1_Click Stack:    at Hungarian.Form1.Button1_Click(Object sender, EventArgs  e) in C:\Documents and Settings\James Foxall\My Documents\Visual  Studio Projects\Form1.vb:line 97 4/8/2002 11:46:47 PM Exception: Arithmetic operation resulted in an overflow. Module: Form1 Method: Button1_Click Stack:    at Hungarian.Form1.Button1_Click(Object sender, EventArgs  e) in C:\Documents and Settings\James Foxall\My Documents\Visual  Studio Projects\Form1.vb:line 97 4/8/2002 11:47:31 PM Exception: Funky crazy custom error Module: Form1 Method: Button1_Click Stack:    at Hungarian.Form1.Button1_Click(Object sender, EventArgs  e) in C:\Documents and Settings\James Foxall\My Documents\Visual  Studio Projects\Form1.vb:line 96 

You can start to see a trend in this exception log. Whoever wrote the Form1 module needs to spend a little more time with the code. The information shown here is the minimum amount you'd want to include in a text file; you might want to include much more. For instance, you might want to include the user name of the person running the program when the exception occurs, or you might want to include the machine name in the log entry. The possibilities are endless. Whatever you choose to put into the text file, make sure it's pertinent information that will help you find and correct the problem.

For clarity, the following is the complete exception handler shown previously, with the inclusion of the exception log code:

Friend Sub HandleException(ByVal strModule As StringByVal As Exception)    ' Purpose   :  Provide a central error-handling mechanism.    ' Accepts   :  strModule - the module in which the error was    '                 encountered (form, class, standard, and so on.)    '              e - the exception that occurred.     Dim strMessage As String    Dim strCaption As String    Try        ' Build the error message.          strMessage = "Exception: " & e.Message & vbCrLf & vbCrLf & _                    "Module: " & strModule & vbCrLf & _                    "Method: " & e.TargetSite.Name & vbCrLf & vbCrLf & _                    "Please notify My Software's tech support " & _                    "at 555-1213 about this issue." & vbCrLf & _                    "Please provide the support technician with " & _                    "information shown in " & vbCrLf & "this dialog " & _                    "box as well as an explanation of what you " & _                    "were" & vbCrLf & "doing when this " & _                    "error occurred."       ' Build the title bar text for the message box. The text includes       ' the version number of the program.        With System.Reflection.Assembly.GetExecutingAssembly.GetName.Version          strCaption = "Unexpected Exception! Version: " & _                       .Major & "." & _                       .Minor & "." & _                       Format(.Revision, "0000")       End With        ' Open a new stream writer to the log file.        Dim objStream As New System.IO.StreamWriter(g_strExceptionLogFileName, _                                                   True)       Dim strLogText As String        ' Create the log text.       strLogText = DateTime.Now & ControlChars.CrLf & _                    "Exception: " & e.Message & ControlChars.CrLf & _                    "Module: " & strModule & ControlChars.CrLf & _                    "Method: " & e.TargetSite.Name & ControlChars.CrLf & _                    "Stack: " & e.StackTrace & ControlChars.CrLf       ' Write the exception message.       objStream.WriteLine(strLogText)       ' Flush the text to the log file.       objStream.Flush()       ' Close the log file.       objStream.Close()       ' Show the error to the user.       MessageBox.Show(strMessage, strCaption, MessageBoxButtons.OK, _                       MessageBoxIcon.Exclamation)    Finally    End Try End Sub 

Once your application is logging error messages, you must decide what you want to do with those logs. If you're on-site with the program, you can manually retrieve copies of the exception logs. Or you can have users e-mail you their logs if they encounter problems. You might even write a program that automatically e-mails the logs to you on a preset schedule, or you might want to write an e-mail interface directly into the central exception handler. Log files can be very useful for locating specific bugs as well as general program errors, and they trivially easy to create; you should seriously consider adding this feature to your programs. You might even elect to include the logging code but turn off the feature by default. You could then enable or disable log file generation via your program's interface or a registry setting.

 

Goals of Exception Handling

The goals of utilizing exception handling are

  • Preventing your program from crashing

  • Gracefully correcting mistakes whenever possible

  • Notifying the user when exceptions occur so that the problems can be addressed

 



Practical Standards for Microsoft Visual Basic. NET
Practical Standards for Microsoft Visual Basic .NET (Pro-Developer)
ISBN: 0735613567
EAN: 2147483647
Year: 2005
Pages: 84

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net