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:
intt i;
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.
When the compiler finds a syntax error, an error message containing the location of the error and a terse explanation will be displayed in the Output window of VS.NET. If the error is caused by something such as an unbalanced parenthesis or bracket (or a missing semicolon in C#), then the actual error may not be on the exact line reported.
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 rears its ugly head.
In order to demonstrate what happens if there is no error handling in place, modify the sample project from this chapter to force some 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++)
to:
for (i = 0; i < books.GetLength(0) + 2; i++)
In VB.NET, change the line:
for i = 0 to books.GetLength(0) - 1
to:
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.
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.
Example 7-9. Custom error code snippet from web.config
<?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.
Example 7-10. CustomErrorPage.htm
<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:
On
Enables custom errors for the entire application.
Off
Disables custom errors for the entire application.
RemoteOnly
Enables custom errors only for remote clients. Local clients will see the generic error page. In this way, developers can see all the possible error information, but end users will see the custom error page.
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.
Example 7-11. Custom error code snippet with <error> subtags from web.config
<?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.
You can override the application-level error pages for any specific page by modifying the Page directive. (Page directives are covered fully in Chapter 6.)
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.
3.142.199.181