Apply Your Knowledge
Key Terms
exception
exception handling
input validation
Exercises
3.1 - Handling Exceptions
Recall that Step by Step 2.5 in Chapter 2 demonstrates the use of common dialog boxes through the creation of a simple rich text editor. This editor allows you to open and save a rich text file. You can also edit the text and change its fonts and colors. The program works fine in all cases except when you try to open or save a file that is already open; in that case, the program throws a System.IO.IOException exception.
The objective of this exercise is to make a robust version of this program that generates a warning about the open file rather than abruptly terminating the program.
Estimated time: 15 minutes
Open a new Windows application in Visual C# .NET. Name it 316C03Exercises.
Add a Windows form to the project. Name the form Exercise3_1.
-
Place five Button controls on the form. Name them btnOpen, btnSave, btnClose, btnColor, and btnFont, and change their Text properties to &Open..., &Save..., Clos&e..., &Color..., and &Font..., respectively. Place a RichTextBox control on the form and name it rtbText. Arrange all the controls as shown in Figure 3.12.
Figure 3.12 This robust version of a simple rich text editor handles the exceptions of System.IO.IOException type.
-
Drag and drop the following components from the toolbox onto the form: OpenFileDialog, SaveFileDialog, ColorDialog, and FontDialog.
-
Switch to the code view and add the following using directive to the top of the program:
using System.IO;
-
Double-click the Open button to attach an event handler to this Click event. Add the following code to the event handler:
private void btnOpen_Click( object sender, System.EventArgs e) { //Allow user to select only *.rtf files openFileDialog1.Filter = "Rich Text Files (*.rtf)|*.rtf"; if(openFileDialog1.ShowDialog() == DialogResult.OK) { try { //Load the file contents //into the RichTextBox control rtbText.LoadFile( openFileDialog1.FileName, RichTextBoxStreamType.RichText); } catch(System.IO.IOException ioe) { MessageBox.Show(ioe.Message, "Error opening file"); } } }
-
Add the following code to handle the Click event of the Save button:
private void btnSave_Click( object sender, System.EventArgs e) { //Default choice for saving file //is *.rtf but user can select //All Files to save with //another extension saveFileDialog1.Filter = "Rich Text Files (*.rtf)|*.rtf|" + "All Files (*.*)|*.*"; if(saveFileDialog1.ShowDialog() == DialogResult.OK) { try { //Save the RichTextBox control's //content to a file rtbText.SaveFile( saveFileDialog1.FileName, RichTextBoxStreamType.RichText); } catch(System.IO.IOException ioe) { MessageBox.Show(ioe.Message, "Error saving file"); } } }
-
Add the following code to handle the Click event of the Close button:
private void btnClose_Click( object sender, System.EventArgs e) { //close the form this.Close(); }
-
Add the following code to handle the Click event of the Color button:
private void btnColor_Click( object sender, System.EventArgs e) { if(colorDialog1.ShowDialog() == DialogResult.OK) { //Change the color of the selected //text. If no text is selected, // change the active color rtbText.SelectionColor = colorDialog1.Color; } }
-
Add the following code to handle the Click event of the Font button:
private void btnFont_Click( object sender, System.EventArgs e) { if(fontDialog1.ShowDialog() == DialogResult.OK) { //Change the font of the selected //text. If no text is selected, //change the active font rtbText.SelectionFont = fontDialog1.Font; } }
-
Insert the Main() method to launch the form. Set the form as the startup object.
-
Run the project. Click on the Open button and try to open an already opened file. An error message appears, warning about the file already being open, as shown in Figure 3.13.
Figure 3.13 Instead of abnormal program termination, you now get an error message about the already open file.
3.2 -Validating User Input
One technique for input validation is to force the user to fix an erroneous field before allowing him or her to move to another field. To achieve this, you can set the Cancel property of the CancelEventArgs argument of the field's Validating event to false.
In this exercise, you create a login form (see Figure 3.14) that accepts a username and password. It forces the user to enter the username. The user should also be able to close the application by clicking the Cancel button, regardless of the validation status of the fields.
Figure 3.14 A nonsticky login form validates the input and allows users to close the application by clicking the Cancel button.
Estimated time: 15 minutes
-
Open a Visual C# .NET Windows application in the Visual Studio .NET IDE. Name it 316C03Exercises.
-
Add a new form to the application. Name it Exercise3_2.
-
Place three Label controls (keep their default names), two TextBox controls (txtUserName and txtPassword), two Button controls (btnLogin and btnCancel), and an ErrorProvider component (errorProvider1) on the form. The ErrorProvider component is placed in the component tray. Arrange the controls in the form as shown in Figure 3.14.
-
Change the ControlBox property of the form to false, the CharacterCasing property of the txtPassword control to Lower, and the CausesValidation property of the btnCancel control to false.
-
Double-click the Form control to attach a Load event handler; add the following code to the event handler:
private void Exercise3_2_Load( object sender, System.EventArgs e) { errorProvider1.SetIconAlignment( txtUserName, ErrorIconAlignment.MiddleLeft); errorProvider1.SetIconAlignment( txtPassword, ErrorIconAlignment.MiddleLeft); }
-
Declare the following variable outside a method block in the class:
//closingFlag is used to check if the //user has clicked the Close button private bool closingFlag = false;
-
Add the following code to the Click event handler of the Cancel button:
private void btnCancel_Click( object sender, System.EventArgs e) { closingFlag = true; this.Close(); }
-
Add the following code to the Click event handler of the Login button:
private void btnLogin_Click( object sender, System.EventArgs e) { string strMessage = String.Format( "The following information:" + "\n\nUserName: {0}\n\nPassword: {1}" + "\n\n can now be passed to the " + "middle-tier for validation", txtUserName.Text, txtPassword.Text); MessageBox.Show(strMessage, "User Input Validation Succeeded"); }
-
Attach the following event handling code to the Validating events of both the txtUserName and txtPassword controls:
private void txtUserNamePassword_Validating( object sender, System.ComponentModel.CancelEventArgs e) { TextBox fieldToValidate = (TextBox) sender; if (!closingFlag) { if(fieldToValidate.Text.Trim().Length == 0) { errorProvider1.SetError( fieldToValidate, "Please enter a value for this field"); e.Cancel = true; } else if ( fieldToValidate.Text.Trim().IndexOf(' ') >=0) { errorProvider1.SetError( fieldToValidate, "You may NOT have spaces in this field"); fieldToValidate.Select(0, fieldToValidate.Text.Length); e.Cancel = true; } } }
-
Attach the following event handling code to the Validated event of both the txtUserName and txtPassword controls:
private void txtUserNamePassword_Validated( object sender, System.EventArgs e) { TextBox fieldToValidate = (TextBox) sender; errorProvider1.SetError( fieldToValidate, ""); }
-
Insert the Main() method to launch the form. Set the form as the startup object.
-
Run the project. Click the Login button, and you are forced to enter the username. However, you can click the Cancel button to close the application.
Review Questions
What is the default behavior of the .NET Framework when an exception is raised?
What is the base class of all exceptions that provides basic functionality for exception handling? What are the two main types of exception classes and their purposes?
Explain the Message and InnerException properties of the Exception class.
What is the purpose of a try-catch block?
How many catch blocks can be associated with a try block? How should they be arranged?
What is the importance of a finally block?
Can you associate custom error messages with the exception types defined by the CLR? If yes, how do you do it?
What are some of the points you should consider before creating Custom exceptions?
What is the importance of the Validating event?
What is the purpose of the ErrorProvider component?
Exam Questions
-
You are creating a data import utility for a personal information system that you recently designed. When the record in the source data file is not in the required format, the application needs to throw a custom exception. You want to keep the name of this exception class as InvalidRecordStructureException. Which of the following classes would you choose as the base class for the custom exception class?
-
ApplicationException
-
Exception
-
SystemException
-
InvalidFilterCriteriaException
-
-
You are assisting a colleague in solving the compiler error that her code is throwing. This is the problematic portion of her code:
try { bool success = GenerateNewtonSeries(500, 0); //more code here } catch(DivideByZeroException dbze) { //exception handling code } catch(NotFiniteNumberException nfne) { //exception handling code } catch(ArithmeticException ae) { //exception handling code } catch(OverflowException e) { //exception handling code }
To remove the compilation error, which of the following ways would you rearrange the code?
-
try { bool success = GenerateNewtonSeries(500, 0); //more code here } catch(DivideByZeroException dbze) { //exception handling code } catch(ArithmeticException ae) { //exception handling code } catch(OverflowException e) { //exception handling code }
-
try { bool success = GenerateNewtonSeries(500, 0); //more code here } catch(DivideByZeroException dbze) { //exception handling code } catch(Exception ae) { //exception handling code } catch(OverflowException e) { //exception handling code }
-
try { bool success = GenerateNewtonSeries(500, 0); //more code here } catch(DivideByZeroException dbze) { //exception handling code } catch(NotFiniteNumberException nfne) { //exception handling code } catch(OverflowException e) { //exception handling code } catch(ArithmeticException ae) { //exception handling code }
-
try { bool success = GenerateNewtonSeries(500, 0); //more code here } catch(DivideByZeroException dbze) { //exception handling code } catch(NotFiniteNumberException nfne) { //exception handling code } catch(Exception ae) { //exception handling code } catch(ArithmeticException e) { //exception handling code }
-
-
You are required to debug a program that contains exception handling code. To understand the program better, you create a stripped-down version of it and include some MessageBox statements that give you clues about the flow of the program's execution. The program has the following code:
try { int num = 100; int den = 0; MessageBox.Show("Message1"); try { int res = num/den; MessageBox.Show("Message2"); } catch(ArithmeticException ae) { MessageBox.Show("Message3"); } } catch(DivideByZeroException dbze) { MessageBox.Show("Message4"); } finally { MessageBox.Show("Message5"); }
Which of the following options describes the correct order of displayed messages?
-
Message1 Message2 Message3 Message4 Message5
-
Message1 Message3 Message5
-
Message1 Message4 Message5
-
Message1 Message2 Message4 Message5
-
-
In your Windows application, you want to determine the type of an exception. You have written the following code:
try { try { throw new ArgumentOutOfRangeException(); } catch(ArgumentException ae) { throw new ArgumentException( "Out of Range", ae); } } catch(Exception e) { MessageBox.Show( e.InnerException.GetType().ToString()); }
When the program containing this code segment is executed, what output is displayed by the message box?
-
System.Exception
-
System.ApplicationException
-
System.ArgumentException
-
System.ArgumentOutOfRangeException
-
-
The Validating event of a TextBox control in your Windows application has the following code:
01 private void textBox1_Validating( object sender, CancelEventArgs e) 02 { 03 try 04 { 05 MyValidatingCode(); 06 } 07 catch(Exception ex) 08 { 09 10 textBox1.Select(0, textBox1.Text.Length); 11 this.errorProvider1.SetError( textBox1, ex.Message); 12 } 13 }
The MyValidatingCode() method validates the contents of the text box. If the contents are invalid, the MyValidatingCode() method throws an exception and retains control in the text box. (The line numbers in the code sample are for reference purposes only.) Which of the following lines of code should be in line 9?
-
e.Cancel = true;
-
e.Cancel = false;
-
textBox1.CausesValidation = true;
-
textBox1.CausesValidation = false;
-
You have designed a windows form that works as a login screen. The form has two TextBox controls, named txtUserName and txtPassword. You want to ensure that user can enter only lowercase characters in the control. Which of the following options would you recommend?
-
Set the form's KeyPreview property to true and 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 both txtUserName and txtPassword. Program this event handler to convert the uppercase letters to lowercase.
-
Use the CharacterCasing property.
-
Use the Char.ToLower() method in the TextChanged event handler.
-
-
You need to create a custom exception class in a Windows application. You have written the following code for the Exception class:
public class KeywordNotFound: ApplicationException { public KeywordNotFoundException() { } public KeywordNotFoundException( string message, Exception inner) : base(message, inner) { } }
A peer reviewer of the code finds that you did not follow some of the best practices for creating a custom exception class. Which of the following suggestions do you need to incorporate? (Choose all that apply.)
-
Name the exception class KeywordNotFoundException.
-
Derive the exception class from the base class Exception instead of ApplicationException.
- Add one more constructor to the class, with the following signature:
public KeywordNotFoundException( string message) : base(message) { }
- Add one more constructor to the class, with the following signature:
public KeywordNotFoundException( Exception inner) : base(inner) { }
-
Derive the exception class from the base class SystemException instead of ApplicationException.
-
In your Windows application, you have created a dialog box that allows users to set options for the application. You have also created a Help button that users can press to get help on various options for the dialog box. You validate the data entered by the user in a text box titled Complex Script. If the user enters an invalid value, you set the focus back in the control by setting the Cancel property of the CancelEventArgs object to true. While you are testing the application, you discover that when you enter invalid data in the text box, you cannot click the Help button unless you correct the data first. What should you do to correct the problem?
-
Set the CausesValidation property of the TextBox control to false.
-
Set the CausesValidation property of the TextBox control to true.
-
Set the CausesValidation property of the Help button to false.
-
Set the CausesValidation property of the Help button to true.
-
-
You are writing exception handling code for 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 the Exception class could help you?
-
HelpLink
-
InnerException
-
Message
-
StackTrace
-
-
Which of the following statements is true regarding the following usage of the throw statement?
catch(Exception e) { throw; }
-
The throw statement catches and rethrows the current exception.
-
The throw statement catches, encapsulates, and then rethrows the current exception.
-
The throw statement must be followed by an exception object to throw.
-
The throw statement transfers control to the finally block that follows the catch block.
-
-
You are creating a Windows form that works as a login screen for an order entry system designed for the sales department of your company. Which of the following strategies would you follow?
-
Design a ValidateUser() method. Throw a new custom exception EmployeeNotFound when the entered username is not in the database.
-
Design a ValidateUser() method. Throw an ArgumentException exception when the user types special characters in the username field or the password field.
-
Design a ValidateUser() method that returns true if the username and password are correct and otherwise returns false.
-
Design a ValidateUser() method. Throw an ApplicationException exception when the entered username is not in the database.
-
-
You want to capture all the exceptions that escape from the exception handling code in your application and log them in the Windows event log. Which of the following techniques would you use?
-
Write all the code of the Main() method inside a try block, attach a generic catch block to that try block, and handle the exception there.
-
Write all the code of the Main() method inside a try block, attach a catch block that catches all exceptions of type Exception, and write code to make an entry in the event log.
-
Program the ProcessExit event handler of the AppDomain class.
-
Program the UnhandledException event handler of the AppDomain class.
-
-
Which of the following is the most robust way to record the unhandled exceptions in an application?
-
Create an entry in the Windows event log.
-
Create an entry in the application's custom log file.
-
Create an entry in a table in a Microsoft SQL Server 2000 database.
-
Send an email message using SMTP.
-
-
The structured exception handling mechanism of the .NET Framework allows you to handle which of the following types of exceptions? (Choose all the answers that apply.)
-
Exceptions from all CLS-compliant languages
-
Exceptions from non-CLS-compliant languages
-
Exceptions from unmanaged COM code
-
Exceptions from unmanaged non-COM code
-
Which of the following statements is true about the following code segment?
const int someVal1 = Int32.MaxValue; const int someVal2 = Int32.MaxValue; int result; checked { result = someVal1 * someVal2; }
-
The code generates an OverflowException exception.
-
The code executes successfully without any exceptions.
-
The code causes a compile-time error.
The code executes successfully, but the value of the resulting variable is truncated.
-
Answers to Review Questions
-
The .NET Framework terminates the application after displaying an error message when an exception is raised.
-
The Exception class is the base class that provides common functionality for exception handling. The two main types of exceptions derived from the Exception class are SystemException and ApplicationException. SystemException represents the exceptions thrown by the CLR, and ApplicationException represents the exceptions thrown by the applications.
-
The Message property describes the current exception. The InnerException property represents an exception object associated with the current exception object. This property is helpful when a series of exceptions are involved because each new exception can preserve the information about the previous exception by storing it in the InnerException property.
-
The try block is used to enclose code that may raise an exception. The catch block handles the exception raised by the code in the try block.
-
Zero or more catch blocks can be associated with a try block. If there is no catch block associated with a try block, a finally block should follow the try block; otherwise, a compile-time error occurs. The catch blocks should be arranged from top to bottom in the order of specific to general exception types; otherwise, a compile-time error occurs.
-
The code contained by the finally block always executes, regardless of whether any exception occurs in the try block. Therefore, you can use the finally block to write cleanup codesuch as closing data connections, closing files, and so onthat needs to happen, regardless of whether an exception occurs.
-
Yes, you can associate custom error messages with the exception classes defined by the CLR in order to provide more meaningful information to the calling code. The constructor of these classes that accepts as its parameter the exception message can be used to pass the custom error message.
-
Custom exceptions should be derived from ApplicationException and should be created only if any of the existing classes do not meet the requirements of your application. The custom exception classes should have names that end with the word Exception and should implement three constructors (a default constructor that takes no arguments, a constructor that takes a string argument, and a constructor that takes a string as well as an Exception object) of the base class.
-
The Validating event is the ideal place for storing the field-level validation logic for a control. The Validating event handler can be used to cancel the event if validation fails, thus forcing the focus to the control. This requires the user to enter correct data.
- The ErrorProvider component in the Visual Studio .NET toolbox can be used to show validation-related error icons and error messages to the user.
Answers to Exam Questions
-
A. When you create a class for handling custom exceptions in your programs, the best practice is to derive it from the ApplicationException class. The SystemException class is for the system-defined exceptions. The Exception class is the base class for both the ApplicationException and SystemException classes and should not be subclassed. For more information, see the section "Creating and Using Custom Exceptions" in this chapter.
-
C. When you have multiple catch blocks associated with a try block, you must write them in the order of most specific to least specific. The catch block corresponding to the ArithmeticException exception should come at the end because it is more general than DivideByZeroException, NotFiniteNumberException, and OverFlowException, which are derived from it. For more information, see the section "The catch Block" in this chapter.
-
B. When an exception occurs in a try block, the program searches for a matching catch block associated with that try block. Because the ArithmeticException type is more general than the DivideByZeroException type, all DivideByZeroException exceptions are handled in the catch block that catches the ArithmeticException exception. In all cases, the finally block is executed. For more information, see the sections "The catch Block" and "The finally Block" in this chapter.
-
D. The message box displays a System.ArgumentOutOfRangeException exception because that is the exception that you caught and wrapped in the InnerException property of the exception that was caught later by the outer catch block. For more information, see the section "The throw Statement" in this chapter.
-
A. When you want to retain the control inside a control after the Validating event is processed, you must set the Cancel property of the CancelEventArgs argument in the Validating event. The correct answer is therefore e.Cancel = true. The CausesValidation property has a different purpose: It is used to decide whether a Validating event is fired for a control. For more information, see the section "The Validating Event" in this chapter.
-
C. The CharacterCasing property, when set to CharacterCasing.Lower for a TextBox control, converts all uppercase letters to lowercase as you type them. It is the preferred way to enforce either lowercase or uppercase input in a text box. For more information, see the section "Other Properties for Validation" in this chapter.
-
A and C. As a good exception handling practice, you should end the name of the exception class with the word Exception. In addition, an exception class must implement three standard constructors. The missing constructor is the one given in Answer C. For more information, see the section "Creating and Using Custom Exceptions" in this chapter.
-
C. When you want a control to respond, regardless of the validation status of other controls, you should set the CausesValidation property of that control to false. Therefore, the Help button should have its CausesValidation property set to false. For more information, see the section "The CausesValidation Property" in this chapter.
-
D. The StackTrace property of the Exception class and the classes that derive from it contain information about the sequence of method calls and the line numbers in which exceptions occur. Therefore, it is the right property to use. For more information, see the section "Understanding Exceptions" in this chapter.
-
A. The throw statement re-throws the current exception. For more information, see the section "The throw Statement" in this chapter.
-
C. It is obvious that the user might make typing mistakes while typing his or her username or password. You should not throw exceptions for these situations; you should instead design a ValidateUser() method that returns a result indicating whether the login is successful. For more information, see the section "Validating User Input" in this chapter.
-
D. To capture all unhandled exceptions for an application, you must program the UnhandledEvent event handler of the AppDomain class. For more information, see the section "Managing Unhandled Exceptions" in this chapter.
-
A. Logging on to the Windows event log is the most robust solution because the other solutions have more assumptions that may fail. For example, your application might loose connectivity with the database or with the SMTP server, or you might have problems writing an entry to a custom log file. For more information, see the section "Managing Unhandled Exceptions" in this chapter.
-
A, B, C, and D. The .NET Framework allows you to handle all kinds of exceptions, including cross-language exceptions, for both CLS- and non-CLS-compliant languages. It also allows you to handle exceptions from unmanaged code, both COM as well as non-COM. For more information, see the section "Understanding Exceptions" in this chapter.
- C. When constant values appear inside the checked statement, they are checked for overflow at compile time. Because you are multiplying the two maximum possible values for integer, the result cannot be stored inside an integer. The compiler detects this problem and generates a compile-time error. For more information, see the section "Handling Exceptions" in this chapter.
Suggested Readings and Resources
-
Visual Studio .NET Combined Help Collection:
-
"Exception Management in .NET"
-
"Exception Handling Statements"
-
"Best Practices for Exception Handling"
-
-
Harvey M. Dietel, et al. C# How to Program. Prentice Hall, 2001.
-
Jeffrey Richter. Applied Microsoft .NET Framework Programming. Microsoft Press, 2001.
-
Exception Management in .NET. msdn.microsoft.com/library/en-us/dnbda/html/exceptdotnet.asp.