7.4 Error Handling
You can and should avoid bugs, but there are runtime errors that cannot be avoided and must be handled. The simplest bugs to find and fix are syntax errors: violations of the rules of the language. For example, suppose you had the following line of code in your C# program:
or this line in your VB.NET program:
dim i as intgr
In either case, when you try to compile the program, you will get a compiler error, because in each case, the keyword for integer is misspelled.
Syntax errors are reduced dramatically when using Visual Studio .NET. Depending on how VS.NET is configured, any code element that isn't recognized is underlined. If Auto List Members is turned on, the incidence of syntax errors is further reduced. Finally, because VB.NET doesn't necessarily require explicit variable declaration, you can turn Option Explicit on to eliminate typos as a source of syntax errors.
Should any syntax errors remain, or if you are using a different editor, then any syntax errors will be caught by the compiler every time you try to build the project. It is nearly impossible for a syntax error to slip by into production code.
More problematic, and often more difficult to catch, are errors in logic. The program successfully compiles and may run perfectly well most of the time, yet still contain errors in logic. The very hardest bugs to find are those that occur least often. If you can't reproduce the problem, it is terribly difficult to find it.
While you will try to eliminate all the bugs from your code, you do want your program to react gracefully when a subtle bug or unexpected problem rears its ugly head.
7.4.1 Unhandled Errors
Go to the code-behind window. Find the for loop that populates the DropDownList in the Page_Load method. Change the test expression to intentionally cause an error at runtime. For example, in C#, change the line:
for (i = 0; i < books.GetLength(0); i++)
for (i = 0; i < books.GetLength(0) + 2; i++)
In VB.NET, change the line:
for i = 0 to books.GetLength(0) - 1
for i = 0 to books.GetLength(0) + 2
In either language, when this code runs it will try to add more items than have been defined in the books array, thus causing a runtime error. While this is not a subtle bug, it will serve to demonstrate how the system reacts to runtime errors.
Now run the program. As expected, an error is generated immediately, and the generic ASP.NET error page is displayed, as shown in Figure 7-17.
This error page is actually fairly useful to the developer or technical support person who will be trying to track down and fix any bugs. It tells you the type of error, the line in the code that is the approximate location of the error, and a stack trace to help in tracking down how that line of code was reached.
7.4.2 Application-wide Error Pages
The previous section showed the default error pages presented for unhandled errors. This is fine for a developer, but if the application is in production, it would be much more aesthetically pleasing if the user were presented with an error page that did not look so intimidating.
The goal is to intercept the error before it has a chance to send the generic error page to the client. This is done on an application-wide basis by modifying the web.config file, which will be described more fully in Chapter 20.
The error-handling configuration information in web.config is contained within the <customErrors> section within the <system.web> section, which is contained within the <configuration> section. A typical <customErrors> section will look like Example 7-9.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.web> . . . <customErrors defaultRedirect="CustomErrorPage.htm" mode="On" />
There are two possible attributes for the <customErrors> section: defaultRedirect and mode.
defaultRedirect is a text string that contains the URL of the page to display in the case of any error not otherwise handled. In Example 7-9, the defaultRedirect page is CustomErrorPage.htm. This example is a very simple HTML page contained in the same application virtual root directory. The contents of this page are shown in Example 7-10.
<html> <body> <h1>Sorry - you've got an error.</h1> </body> </html>
If the custom error page to be displayed is not in the application virtual root, then you need to include either a relative or a fully qualified URL in the defaultRedirect attribute.
mode is an attribute that enables or disables custom error pages for the application. It can have three possible values:
If you edit your web.config file to look like Example 7-9, then put CustomErrorPage.htm in your application virtual root and run the program. Instead of Figure 7-17, you will see something like Figure 7-18.
Obviously, you'll want to put more information on your custom error page, such as instructions or contact information, but you get the idea. It is also possible to show dynamic information about the error on the custom error page.
You can even use a different custom error page for different errors. To do this, you need to include one or more <error> subtags in the <customErrors> section of web.config. You might, for example, modify web.config to look like the code snippet in Example 7-11.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.web> . . . <customErrors defaultRedirect="CustomErrorPage.htm" mode="On" > <error statusCode="400" redirect="CustomErrorPage400.htm"/> <error statusCode="404" redirect="CustomErrorPage404.htm"/> <error statusCode="500" redirect="CustomErrorPage500.htm"/> </customErrors>
Copy CustomErrorPage.htm three times and rename the copies to the filenames in the <error> subtags in Example 7-11. Edit the files so that each displays a unique message.
Run the program again with the intentional error in the for loop still in place. You should see something like Figure 7-19.
Fix the error in the for loop so that the program will at least load correctly. Then run the program and click on the hyperlink you put on the test page. Remember that that control is configured to link to a nonexistent .aspx file. You should see something like Figure 7-20.
Be aware that you can only display custom error pages for errors generated on your server. So, for example, if the hyperlink had been set to a nonexistent page, say, http://TestPage.comx (note the intentional misspelling of the extension), you will not see your custom error page for error 404. Instead you'll see whatever error page for which the remote server or your browser is configured. Also, you can only trap the 404 error if the page you are trying to link to has an extension of .aspx.
7.4.3 Page-Specific Error Pages
You can override the application-level error pages for any specific page by modifying the Page directive. (Chapter 6 fully discusses page directives.)
Modify the Page directive in the WebForm1.aspx page so that it appears as follows (note the highlighted ErrorPage attribute, which has been added):
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="DebuggingApp.WebForm1" Trace="false" ErrorPage="PageSpecificErrorPage.aspx" %>
If there is an error on this page, the PageSpecificErrorPage.aspx page will be displayed. If there is an application-level custom error page defined in web.config, it will be overridden by the Page directive.