Handling Exceptions in the .NET Framework
Date: Jun 27, 2003
Terms you'll need to understand:
Exception
Try code block
Catch code block
Finally code block
Throw statement
Validation
KeyPress
ErrorProvider
Techniques you'll need to master:
Knowing the default application behavior that occurs when an unhandled exception is encountered.
Understanding the use of Try, Catch, and Finally code blocks.
Understanding the four techniques of user input validation: control choice, control state, keystroke validation, and full control validation.
In a perfect world, your code would run correctly every time. But in the real world, you need to handle unexpected problems when your code is running. The user might delete a critical file or enter invalid data. A network link to a server might fail just as you're transferring data. Or perhaps you simply didn't allow for a particular rare circumstance in your code.
Fortunately, the .NET Framework offers a robust set of tools for dealing with these unexpected problems. In this chapter, we'll look at two facets of dealing with problems in .NET. First, we'll demonstrate the programming that you can do to handle errors, allowing the user to make corrections when something goes wrong. Then, we'll demonstrate how you can use validation techniques to prevent bad data from being entered into your application in the first place. Consistent use of these techniques will help make your applications more robust and reliable.
Exceptions Overview
When an application encounters an unexpected situation (such as a missing file or input parameter) or a logical error (performing a division-by-zero operation, for example), by default the application will terminate and generate an error display like the one shown in Figure 3.1.
Figure 3.1 By default, .NET displays an error message and terminates the application when any error occurs.
Unhandled errors in an application can result in unexpected termination, lost data, and potentially even create security holes if input values are not properly restricted. The Common Language Runtime (CLR) represents all errors as exceptions. An exception is an instance of the Exception class (or a class that inherits from the Exception class). The Framework class library (FCL) includes a large number of standard exception classes that encapsulate information about common errors. Working with instances of these classes allows the developer to provide robust error-handling solutions.
The .NET Framework provides two general classes or exceptions that derive from the common Exception class:
ApplicationExceptionExceptions thrown by the application.
SystemExceptionExceptions thrown by the CLR.
Both of these child classes enjoy the same properties and are differentiated only in the source of the exception they represent. Table 3.1 details some of the more common properties of the Exception classes.
Table 3.1 Important Members of the Exception Class
Property |
Description |
HelpLink |
The URL for a help file associated with this exception. |
InnerException |
An exception associated with the exception whose InnerException property you are accessing. This is helpful when a series of exceptions are involved. Each new exception can preserve the information about the previous one by storing it in this property. |
Message |
A message explaining the error and possibly offering ways to resolve it. |
Source |
The name of the application that caused the error. |
StackTrace |
Specifies where the error occurred. If debugging information is available, the stack trace includes the source file and program line number, along with other information. |
TargetSite |
The method that threw the exception. |
Handling Exceptions
One of the most fundamental and often most complex tasks of a developer is to design exception-handling procedures in order to allow an application to recover gracefully from an unexpected or disallowed condition.
The .NET Framework allows exception handling to be performed between languages, across multiple computers, and even through integration with COM and other legacy solutions. Within Visual Basic .NET, the most common methods of exception handling involve the Try, Catch, and Finally blocks in addition to the Throw statement.
TIP
The Try, Catch, and Finally blocks must be consecutive within code. You may not have intervening code separating these blocks when configuring event-handling solutions within your code. Everything between the Try and End Try keywords is part of a single error-handling unit.
The Try Block
When code is processed that may generate an exception, the code may be placed within a Try block, which must in turn be followed by one or more Catch blocks or a Finally block. Exceptions raised cause the CLR to search for the nearest Try block (which may be nested within one another) and then pass control to the following Catch block or on to the Finally block if no Catch block is present in the code.
A Try block in its most basic form looks like this:
Try ' Code that may cause an exception Catch ' Code that handles any exception End Try
Any normal code may be placed within the Try block, including another Try block or calls to methods including Try blocks of their own. When an exception occurs, the CLR will find the nearest Try block and pass control to the following associated exception-handling blocks.
CAUTION
A Try block must be followed by one or more Catch blocks or by a Finally block.
The Catch Block
After an exception is encountered within a Try block, control is passed to the following Catch blocks or to the Finally block. Catch blocks are evaluated in order until a match to the exception type is made. A particular exception might be matched by many different Catch blocks of varying levels of generality.
For example, a DivideByZeroException might match a Catch block for DivideByZeroException, ArithmeticException, SystemException, or Exception. These are all increasingly general exception classes that contain the specific DivideByZeroException. If no matching Catch block can be found, the exception is passed back to the code that raised the exception and is considered an unhandled exception, which is discussed in greater detail later in this chapter.
NOTE
The default behavior for an unhandled exception is to cause the program to terminate with an error message.
TIP
Because Catch blocks are evaluated in the order that they occur in your code, you must always place the most specific exceptions first if you have multiple Catch blocks. Otherwise, the code will not compile.
A Try block followed by some Catch exception blocks might look like this:
Private Sub btnCalculate_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCalculate.Click Try Dim decMiles As Decimal = Convert.ToDecimal(txtMiles.Text) Dim decGallons As Decimal = Convert.ToDecimal(txtGallons.Text) Dim decEfficiency As Decimal = decMiles / decGallons txtEfficiency.Text = String.Format("{0:n}", decEfficiency) ' each try block should at least have one catch or finally block ' catch blocks should be in order of specific to the generalized ' exceptions. Otherwise compilation generates an error Catch fe As FormatException Dim msg As String = String.Format("Message: {0}" & _ vbcrlf & "Stack Trace: " & vbcrlf & " {1}", _ fe.Message, fe.StackTrace) MessageBox.Show(msg, fe.GetType().ToString()) Catch dbze As DivideByZeroException Dim msg As String = String.Format("Message: {0}" & _ vbcrlf & " Stack Trace: " & vbcrlf & " {1}", _ dbze.Message, dbze.StackTrace) MessageBox.Show(msg, dbze.GetType().ToString()) ' catches all CLS-compliant exceptions Catch ex As Exception Dim msg As String = String.Format("Message: {0}" & _ vbcrlf & " Stack Trace: " & vbcrlf & " {1}", _ ex.Message, ex.StackTrace) MessageBox.Show(msg, ex.GetType().ToString()) ' catches all other exceptions including ' non-CLS-compliant exceptions Catch ' just rethrow the exception to the caller Throw End Try End Sub
Here, an exception raised within the code is thrown to the Catch blocks in order to see if a match is made. The inclusion of the Catch block that uses the general Exception class will prevent an unhandled exception. When this code is compiled and run, an input zero value (DivideByZeroException), a nonnumeric value (FormatException), or a very large numeric value (OverflowException, caught by the Catch block as an exception) will not cause the program to terminate. A message will be returned to the user and the application will continue to function.
All languages that follow the Common Language Specification (CLS) will generate an exception that derives from System.Exception. The final Catch block in the code example (which does not specify an exception type at all) is included to handle exceptions generated by possible nonCLS-compliant languages. An unspecified Catch block is the most general form of Catch possible and should always be the last Catch block if multiple Catch blocks are present, because the first matching Catch block will be the one performed.
The Finally Block
The Finally block includes code that will run regardless of whether an exception is raised. This is a good location for cleanup code that will close open files or disconnect database connections to release held resources.
The following is an example of code that includes a Finally block:
Private Sub btnSave_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnSave.Click ' A StreamWriter writes characters to a stream Dim sw As StreamWriter Try sw = New StreamWriter(txtFilename.Text) ' Attempt to write the textbox contents in a file Dim strLine As String For Each strLine In txtText.Lines sw.WriteLine(strLine) Next ' This line only executes if there were no exceptions so far MessageBox.Show("Contents written, without any exceptions") ' Catches all CLS-compliant exceptions Catch ex As Exception Dim msg As String = String.Format( _ "Message: {0}" & vbcrlf & " Stack Trace: " & vbcrlf & _ " {1}", ex.Message, ex.StackTrace) MessageBox.Show(msg, ex.GetType().ToString()) GoTo endit ' The finally block is always executed to make sure that the ' resources get closed whether or not an exception occurs. ' Even if there is a goto statement in a catch or try block the ' finally block is first executed before the control goes to the label Finally If Not sw Is Nothing Then sw.Close() End If MessageBox.Show( _ "Finally block always executes whether or not exception occurs") End Try EndIt: MessageBox.Show("Control is at label: end") End Sub
The Finally block may also be used in conjunction with a Try block, without any Catch blocks. Exceptions raised would be returned as unhandled exceptions in this case. An example of the simplest form of this follows:
Try ' Write code to allocate some resources Finally ' Write code to Dispose all allocated resources End Try
The Throw Statement
The Throw statement can be used to explicitly throw an exception within your code. It can be used in order to re-throw a caught exception to perform a task such as generating an Event Log entry or sending an email notification of the exception, or it may be used in order to raise a custom exception explicitly defined within your code.
NOTE
Exceptions should only be handled or explicitly thrown when doing so improves application usability and robustness. Evaluation of exception-handling code adds to the resource requirements needed to run your application and can rapidly become "too much of a good thing."
Here's an example of a Throw statement in its simplest form being used to re-throw a caught exception:
Catch ex As Exception ' TODO: Add code to write to the Event Log Throw
To use the Throw statement with a custom error message, you may create something like this:
Dim strMessage As String = "EndDate should be greater than the StartDate" Dim exNew As ArgumentOutOfRangeException = _ New ArgumentOutOfRangeException(strMessage) Throw exNew
NOTE
The .NET Framework CLR includes many standard exception types, but on occasion it is necessary or desirable to create a custom exception to address a specific need within your code. This should be done only if there is not already an existing exception class that satisfies your requirements. Any new custom exception should use the System.ApplicationException class as its base class.
Managing Unhandled Exceptions
In Chapter 4, "Components and .NET Assemblies," we discuss the AppDomain class in detail. This class allows for response to events such as when an assembly is loaded or unloaded and when an unhandled exception occurs. When an unhandled exception occurs, it raises an UnhandledException event within the containing AppDomain. This event passes information back to your code in an UnhandledExceptionEventArgs object. This gives you one last chance to work with an exception, even if no Catch block exists to trap the error.
Table 3.2 details the more important properties of the UnhandledExceptionEventArgs class.
Table 3.2 Important Properties of the UnhandledExceptionEventArgs Class
Property |
Description |
ExceptionObject |
Receives the unhandled exception object corresponding to the current domain |
IsTerminating |
A Boolean value that indicates whether the CLR is terminating |
An event handler may be attached to the UnhandledException event to take custom actions such as writing the exception-related information to a log file. A log maintained over a period of time may help you to analyze and identify patterns providing useful debugging information. Several methods may be used to log event-related information, including the following:
Windows Event Log
Custom log files
Databases such as SQL Server 2000
Email notifications
The Windows Event Log provides the most dependable method of logging, because it's a core part of the operating system with few dependencies. If you log to a file, an email, or a database, your logging might fail due to loss of network connectivity or file access.
To log information to the Event Log, you can use the EventLog class. The EventLog class allows your code to write to the Windows Event Logs (Application, System, and Security) available in Windows 2000 and later versions of the operating system.
CAUTION
The option to use the EventLog class is not available in older versions of the Windows operating system, such as Windows 98, and therefore should not be used if the application will be deployed on legacy platforms.
Table 3.3 details some of the more important members of the EventLog class.
Table 3.3 Important Members of the EventLog Class
Member |
Type |
Description |
Clear |
Method |
Removes all entries from the Event Log and leaves it empty |
CreateEventSource |
Method |
Creates an event source that you can use to write to a standard or custom Event Log |
Entries |
Property |
Gets the contents of the Event Log |
Log |
Property |
Specifies the name of the log to read from or write to |
MachineName |
Property |
Specifies the name of the computer on which to read or write events |
Source |
Property |
Specifies the event source name to register and use when writing to the Event Log |
SourceExists |
Method |
Specifies whether the event source exists on a computer |
WriteEntry |
Method |
Writes an entry in the Event Log |
Validating User Input
In order to make your application as robust as possible, the best solution to invalid or incorrect user input is to prevent the entry of "bad" data as often as possible. Validating user input before it is evaluated provides a better solution than complex exception-handling code that may add a great deal of resource overhead to your program. Here are the four basic techniques used to validate user input:
Restricting the available values by using the proper type of control, configured with a specific list of allowed values. Controls such as RadioButtons, ListBoxes, ComboBoxes, and CheckBoxes are often used for this type of validation. Configuring the properties of the controls allows for additional restriction of user input, such as controlling the case or length of text box input.
Restricting data entry through controls by enabling or disabling them based on the state of other controls. As an example of this technique, a set of controls allowing for the entry of address information might remain disabled until a valid customer ID has been selected in another control.
Capturing and evaluating user keystrokes and allowing only acceptable values to be recognized. This might be used to prevent the entry of symbols or alphabetic characters within a control that should hold only numeric characters.
Evaluating a control's data as a whole and warning the user of incorrect or unacceptable values. This is often used to warn a user when attempting to change focus from the control or close the form.
Control-Based Validation
You can restrict the allowable values within a control by using the properties that we discussed in Chapter 2, "Controls on Forms." In addition to simply restricting input to a selection from a list of values, configuration of control properties may be used in order to further limit possible input values. Of note are the CharacterCasing and MaxLength properties used in text-input controls such as the TextBox control.
CharacterCasing
The CharacterCasing property of a TextBox control may be used to force all input alphabetic characters to a particular case. The options for the CharacterCasing property are Normal (the default, which does not change the case of input characters), Upper (which forces all input to uppercase), and Lower (which forces all input to lowercase).
MaxLength
The MaxLength property of a TextBox or ComboBox control is used to restrict the maximum number of characters the user can input into the control. A value of zero (the default) specifies no specific limit to the number of characters that may be input by the user. This property does not restrict the length of values that may be input programmatically.
Control-Access Restriction
Manipulating access properties such as the Enabled and ReadOnly properties can be used to restrict data entry access within a control. When a control's Enabled value is set to False, it cannot receive focus. If the ReadOnly property of a TextBox control is set to True, it may still receive focus, allowing users to scroll through its contents while preventing changes.
Keystroke-Level Validation
When a user presses a key, three events are fired in order:
KeyDown
KeyPress
KeyUp
The KeyPress event may be used in order to intercept input keyboard characters and perform validation tasks through the use of the KeyPressEventArgs class before the KeyUp event is handled. Table 3.4 details some important properties of the KeyPressEventArgs class.
Table 3.4 Important Properties of the KeyPressEventArgs Class
Property |
Description |
Handled |
Indicates whether the event has been handled. |
KeyChar |
The character value corresponding to the pressed key. |
The KeyPress event only fires for keys that generate character values, excluding function, control, and cursor-movement keys. To respond to the excluded keys, you must use the KeyDown and KeyUp events instead. These use the properties of the KeyEventArgs class, detailed in Table 3.5.
Table 3.5 Important Properties of the KeyEventArgs Class
Property |
Description |
Alt |
True if the Alt key is pressed; otherwise False. |
Control |
True if the Ctrl key is pressed; otherwise False. |
Handled |
Indicates whether the event has been handled. |
KeyCode |
The keyboard code for the event. Its value is one of the values specified in the Keys enumeration. |
KeyData |
The key code for the pressed key, along with modifier flags that indicate the combination of Ctrl, Shift, and Alt keys that were pressed at the same time. |
KeyValue |
An integer representation of the KeyData property. |
Modifiers |
Modifier flags that indicate which combination of modifier keys (Ctrl, Shift, and Alt) were pressed. |
Shift |
True if the Shift key is pressed; otherwise, False. |
NOTE
By default, only the control with the focus will respond to the KeyDown, KeyPress, and KeyUp events. If you set the KeyPreview property of a form to True, then the form will handle the same three events before the control with the focus handles them, thus allowing two tiers of keystroke-level validation.
Field-Level Validation
Validation may also be performed to include the entire value entered within a control by configuring validation code to run before focus is lost or the form is closed. When a user enters or leaves a field, the following events occur in order:
Enter (the focus is about to enter the control)
GotFocus (the focus has entered the control)
Leave (the focus is about to leave the control)
Validating (the data in the control is ready to validate)
Validated (the data has been validated)
LostFocus (the focus has left the control)
Of these events, the Validating event is most important for validating user input. That's because code within this event can halt the chain of events and prevent the user from moving on until any error is corrected.
The Validating Event
The Validating event is ideal for input value validation, as you may write code to check the value presented and display an error message to the user, or prevent the loss of focus from the current control until the value has been corrected.
The Focus method of the control may be used in order to redirect focus back to the same control programmatically, and the Cancel property of the CancelEventArgs object may be set to True, preventing the transfer of focus away from the current control.
TIP
Closing a form fires the Validating event. If you set the Cancel property to True during a Validating event when the form is being closed, this will prevent the form from closing. You can use the Closing event of the form to determine whether the form is closing and disable validation in this case, if you like.
The Validated event occurs after validation has occurred and may be used to perform actions based on the validated values, such as enabling or disabling other controls, as discussed previously in this section.
The CausesValidation Property
When using the Validating event to retain the focus in a control until a valid input value is received, you may prevent the user from being able to obtain help on what constitutes a valid input value by clicking another control such as the Help button in the toolbar. This is a result of the default setting (True) of the CausesValidation property of the Button control.
If you set the CausesValidation property of the Help Button control to False, the control may act without first triggering the Validating event in the control with current focus.
The ErrorProvider Component
The ErrorProvider component provided within the Visual Studio .NET toolbox allows for the display of error-validation messages using a small icon that includes a message that appears as a ToolTip when the user hovers his or her cursor over the displayed icon. Table 3.6 details the more important members of the ErrorProvider class.
Table 3.6 Important Members of the ErrorProvider Class
Member |
Type |
Description |
BlinkRate |
Property |
Specifies the rate at which the error icon flashes. |
BlinkStyle |
Property |
Specifies a value indicating when the error icon flashes. |
ContainerControl |
Property |
Specifies the parent control of the ErrorProvider control. |
GetError |
Method |
Returns the error description string for the specified control. |
Icon |
Property |
Specifies an icon to display next to the parent control. The icon is displayed only when an error description string (SetError) has been set for the parent control. |
SetError |
Method |
Sets the error description string for the specified control. |
SetIconAlignment |
Method |
The location at which to place an error icon with respect to the control. |
SetIconPadding |
Method |
The amount of extra space to leave between the specified control and its error icon. |
Use of this component has many advantages over opening separate MessageBox components for each possible error, which may confuse users and complicate the desktop. The ErrorProvider component provides a simple user-friendly display that rapidly draws a user's attention to the control failing input validation. Figure 3.2 shows a form including an ErrorProvider component.
Figure 3.2 A form displaying an example of the ErrorProvider component.
You may be tempted to omit validation from your applications. After all, if the user does exactly what you expect, your validation code will never be invoked. But generally speaking, this is a false economy. Users will find many ways to enter data that you never dreamed of. Validation code provides you with a way to correct problems immediately, and it can cut down on costly customer support.
Practice Questions
Question 1
You have created the following code segment:
Try ' Write code to allocate some
resources Finally ' Write code to Dispose all allocated
resources End Try
Which of the following will result from compiling this code, assuming all other code for your form works properly?
The code will generate an error because it lacks a Catch block.
The code will generate an error because it lacks a Throw statement.
The code will generate an error because the Finally block does not follow the End Try statement.
The code will compile without an error.
Answer D is correct. The code will compile properly because it includes both a Try and a Finally block. Answer A is incorrect because a Try block must have either one or more Catch blocks or a Finally block (or both). Answer B is incorrect because the Throw statement is used to explicitly raise an error and is not required. Answer C is incorrect because the Finally block must follow the Try and Catch blocks but remain within the defined Try block terminated by the End Try statement.
Question 2
You have created a code segment that includes several MessageBox statements that detail the flow of its execution. The program has the following code:
Try Dim num As Integer = 100 dim den as Integer = 0 MessageBox.Show("Message1") Try Dim res As Integer = num / den MessageBox.Show("Message2") Catch ae As ArithmeticException MessageBox.Show("Message3") End Try Catch dbze As DivideByZeroException MessageBox.Show("Message4") Finally MessageBox.Show("Message5") End Try
Which of the following is the order of messages that are generated when you run this code?
- Message1
Message2
Message3
Message4
- Message5
Message1
Message3
Message5
- Message1
Message4
Message5
Message1
- Message2
Message4
Message5
Answer B is correct. The code will generate Message1 before entering the Try block, the attempted division by zero encountered by the Catch as ArithmeticException block will generate Message3, and the Finally block of code will generate Message5. Answers A and C are incorrect because they assume that all Catch blocks will be evaluated, rather than only the first matching exception Catch block. Answer D is incorrect because it fails to catch the first matching exception and instead includes the generation of Message2, which never occurs due to the raising of the division-by-zero error just before, and the generation of Message4, which never occurs because it falls after another matching Catch statement.
Question 3
You are designing a complex membership information form and want to provide a user-friendly interface while also notifying users when invalid information has been input. Which control should you use to display information about validation failures?
ToolTip
Label
LinkLabel
ErrorProvider
Answer D is correct. The ErrorProvider component provides a user-friendly notification for field validation, showing a small warning icon and displaying a ToolTip detailing the validation failure when the cursor is hovered over this icon. Answers A, B, and C are all incorrect.
Question 4
How should you arrange Catch blocks?
Only one Catch block for each Try code block, located after the Try code block but before the End Try statement.
Several Catch blocks within one Try code block, arranged starting with Exception and ending with the most specific exception.
Several Catch blocks within one Try code block, arranged starting with the most specific exception and ending with Exception.
Catch blocks should be used only when a Finally block is not used.
Answer C is correct. One or more Catch blocks may be used with a Try code block, arranged in order from the most specific exception to the most general because the first match will be used for evaluation. Answer A is incorrect because you may associate more than one Catch block with a Try block. Answer B is incorrect because it specifies a reversed order, starting with Exception. Nothing would ever be evaluated past the first Catch block, because Exception includes all other more-specific exceptions. Answer D is incorrect because Catch and Finally blocks may both be used if desired.
Question 5
You have designed a logon form with two TextBox controls named txtUserName and txtpassword. You want to ensure that the user can only enter lowercase characters in the controls. Which of the following solutions will fulfill this requirement using the simplest method?
Program the KeyPress event of the form to convert uppercase letters to lowercase letters.
Create a single event handler that is attached to the KeyPress event of the form. Program this event handler to convert the uppercase letters to lowercase.
Set the CharacterCasing property of the controls to Lower.
Use the CharacterCasing method of the controls to convert the letters to lowercase.
Answer C is correct. The simplest method to accomplish this requirement is to set the CharacterCasing property of the two controllers to Lower so that all input characters will be forced to lowercase. Answers A and B could be used to accomplish this task, but this would not be the simplest solution available. Answer d is incorrect because there is no CharacterCasing method for TextBox controls. CharacterCasing is a property that accepts values of Normal, Lower, or Upper.
Question 6
Which of the following events will fire when the Insert key is pressed? [Select all correct answers.]
KeyDown
KeyPress
KeyUp
Answers A and C are correct. When control and cursor navigation keys are pressed, only the KeyDown and KeyUp events are fired. Answer B is incorrect because the KeyPress event occurs only when a keyboard key generates a character.
Question 7
You have a TextBox control and a help button that the user can click to get help on allowable values. You validate the data entered by the user in the TextBox control, and if the user enters an invalid value you set the focus back in the control using the Cancel property of CancelEventArgs. A user reports that once he enters invalid data in the text box, he cannot click the help button. What should you do to correct the problem?
Set the CausesValidation property of the text box to False
Set the CausesValidation property of the text box to True
Set the CausesValidation property of the help button to False
Set the CausesValidation property of the help button to True
Answer C is correct. By setting the CausesValidation property of the help button to False, you allow it to act without first firing the Validating event in the text box, which would return the focus to the text box. Answers A and B are incorrect because changing the CausesValidation property of the text box will not affect the ability of the help button to be selected. Answer D is incorrect because setting the CausesValidation property of the help button to True (the default value) would result in the same problem experienced by the user.
Question 8
Your program contains the following code (line numbers are for reference only):
1 2 Try 3 4 Catch ex As Exception 5 6 Finally 7 8 End Try
At which lines could you insert a Throw statement to explicitly raise an exception? [Select all correct answers.]
Line 1
Line 3
Line 5
Line 7
Answers A, B, and C are correct. You can use a Throw block to raise a custom error whenever there isn't an unhandled error already pending. You should not use the Throw statement within the Finally block to explicitly raise a custom error because it is possible to have unhandled errors already when in the Finally block of code. Therefore, answer D is incorrect.
Question 9
You have an order-entry form. When an exception occurs, you want to get information about the sequence of method calls and the line number in the method where the exception occurs. Which property of your custom exception class that derives from the ApplicationException class should be used?
HelpLink
InnerException
Message
StackTrace
Answer D is correct. The StackTrace property of the Exception class provides information about the method call sequence and the line number where the exception occurred. Answer A is incorrect because the HelpLink property specifies the URL for an associated help file. Answer B is incorrect because the InnerException property details an exception associated with the raised exception. Answer C is incorrect because the Message property is used to explain the error or offer possible corrective actions.
Question 10
You want to log events generated by exception-handling code within your application, which will run on standalone systems running Windows 98 and Windows 2000. Which of the four methods of logging is the best single solution able to fulfill this requirement?
Using the Windows Event Log
Using custom log files
Using a database such as SQL Server 2000
Using email notifications
Answer B is correct. The best solution in this scenario is to use a local custom log file. Answer A is incorrect because some of the systems are running Windows 98, which does not support logging using the Event Log. Answers C and D are incorrect because standalone systems will not have network access to allow for the connection to a databases or the transmission of SMTP messages.
Need to Know More?
Gunderloy, Mike. MCAD/MCSD Training Guide 70-306: Developing and Implementing Windows-Based Applications with Visual Basic .NET and Visual Studio .NET. Que. Indianapolis, IN, 2002. ISBN 0789728192.
Introduction to exception handling in Visual Basic .NET:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/
vbtchexceptionserrorsinvisualbasicnet.asp.