devxlogo

Errors In Your ASP.NET Code? Don’t Throw a Fit, Throw an Exception!

Errors In Your ASP.NET Code? Don’t Throw a Fit, Throw an Exception!

rror handling, paying taxes, and root canals. Each one conjures up a number of negative mental images?some real, some imagined. While I cannot do much to ease the pain of paying taxes or reduce the suffering you might experience during a root canal, this article will enlighten you regarding the ins and outs of error handling in ASP.NET.

Errors you need to concern yourself with fall into two distinct error types?handled errors and unhandled errors. A handled error occurs within your application?you are ready for it and have code in place to take action upon it. For example, maybe you have coded your application to divide one number by another. What if the second number is 0? A divide by zero error will occur and hopefully you will have code in place to handle such a problem. Unhandled errors are those errors that you cannot foresee happening. An example is an incorrectly typed URL reference for a page on your Web site that results in a “404 Page Not Found” error. Hopefully you will have the pieces in place that will direct the user to a much cleaner and more refined page than the default “404 Page Not Found” page.

Fast Facts
The cornerstone on which structured error handling is built is the Try…Catch…Finally code block.

Let’s start by discussing the language constructs available to handle errors within ASP.NET applications. We will take a look at system exception objects, the TryCatchFinally commands, and creating you own Exception objects.

Errors and Exceptions
While the terms error and exception are often used interchangeably, there is a distinct difference between the two. An error happens during the execution of a block of program code and alters the normal program flow, thus creating an Exception object. When the flow of a program is interrupted by an error, the program will search for exception handling code to tell the program how to react. Simply put, an error is an event. That event creates an object called an exception. This Exception object contains information about the error including when and where it occurred.

The section of the web.config file is your last chance to handle an unexpected error.

Unlike throwing a punch, you will often hear the phrase “throwing an exception.” This means that an error occurred in a code block and an Exception object was created.

The generic Exception class from which all Exception objects are derived is the System.Exception class. It contains a number of properties designed to give you an easy way to capture and manage information about the Exception object. Table 1 lists System.Exception properties.

Table 1: System.Exception properties

Property

Description

HelpLink

Gets or sets a link to the Help file associated with this exception

InnerException

Gets the Exception instance that caused the current exception

Message

Gets a message that describes the current exception

Source

Gets or sets the name of the application or the object that causes the error

StackTrace

Gets a string representation of the items on the call stack at the time the current exception was thrown

TargetSite

Gets the method that throws the current exception

Structured vs. Unstructured Error Handling
Visual Basic .NET and ASP.NET support structured error handling. Structured error handling uses a control structure that acts as the exception handling mechanism. This structure allows your program to determine which type of exception was thrown and act accordingly.

Unstructured error handling is the type of error handling supported in prior versions of Visual Basic and VBScript. It is comprised of an Err object and commands such as On Error, Resume, and Error. This article will not discuss the details of unstructured error handling since structured error handling is the preferred method to trap and manage errors.

Try…Catch…Finally Block
The cornerstone upon which structured error handling is built is the Try…Catch…Finally code block. This control structure tests a block of code and if an error occurs, throws an exception.

The Try command signifies the beginning of a block of code. If an error occurs during the execution of the Try block of code, an exception object is created and the appropriate Catch line handles the exception. If the code in the Try command executes without error, the optional Finally code runs. The Finally code executes regardless of whether or not an exception was thrown. It will also execute after an Exit Try and Exit Sub.

   Try       'Code to try and run   Catch ExceptionObject As Exception [Filters]       'Handle the problem here   Finally       'Tie up any loose ends here like closing       'a database connection   End Try

Catch identifies one or more exceptions that may have been thrown. You can use any number of Catch statements, each taking one of three possible forms: Catch, Catch…As, and Catch…When. If an exception does occurs, the Catch statements are evaluated in the order they appear within the Try…Catch…Finally code block, so you should always list your Catch clauses in order, from the more specific down to the more general. A good programming practice is to always use the following as the last Catch statement in a group of Catch statements.

   Catch ex As Exception       'Code to handle the exception here

Optionally, the Catch statement can include a When clause. The When clause is followed by a Boolean expression, and the exception is only handled if the When expression evaluates to True. The opposite is NOT true though. Just because the expression evaluates to true does NOT mean the Catch code will run. In the following example, if the user enters 20 in the txtCustomerRequest TextBox then intBananas ends up with 0 after the calculation in the Try block.

   Dim intBananas As Integer = 20   Try     intBananas = intBananas - Me.txtRequest.Text   Catch ex As Exception When intBananas = 0     Response.Write("DOH!! Yes, we have no bananas!")     Exit Sub   Catch ex As Exception When intBananas < 10     Response.Write("Time to order more bananas!")     Exit Sub   Catch ex As Exception     Response.Write("Uh oh... unexpected problem")     Exit Sub   Finally     Response.Write("mmmmmm bananas!!!")   End Try

If no error occurs during the calculation in the Try block, the Catch clause with "When intBananas = 0" does NOT fire.

The optional Finally code block is always the last code to be executed as control leaves a Try...Catch...Finally code block. This is true whether or not an unhandled exception occurs or if an Exit Try statement is encountered. In the revised code, a Finally clause has been added and will fire whether or not a calculation error occurred.

   Dim intBananas As Integer = 20   Try     intBananas = intBananas - Me.txtRequest.Text   Catch ex As Exception When intBananas = 0     Response.Write("DOH!! Yes, we have no bananas!")     Exit Sub   Catch ex As Exception When intBananas < 10     Response.Write("Time to order more bananas!")     Exit Sub   Catch ex As Exception     Response.Write("Uh oh... unexpected problem")     Exit Sub   Finally     Response.Write("mmmmmm bananas!!!")   End Try

Common Exception Types
There are a number of different exception types in the .NET Framework. Table 2 lists a few of the more common exception classes and their derived classes, if any.

Table 2: Common exception types

Exception Class

Description

Derived Classes

ArgumentException

Generated when at least one of the arguments passed to a method is not valid

ArgumentNullException ArgumentOutOfRangeException ComponentModel.InvalidEnumArgumentException DuplicateWaitObjectException

ArithmeticException

Generated by error occurring in an arithmetic, casting, or conversion process

DivideByZeroException NotFiniteNumberException OverflowException

Data.DataException

Generated by an error using ADO.NET components

Data.ConstraintException Data.DeletedRowInaccessibleException Data.DuplicateNameException Data.InRowChangingEventException Data.InvalidConstraintException Data.InvalidExpressionException Data.MissingPrimaryKeyException Data.NoNullAlllowedException Data.ReadOnlyException Data.RowNotInTableException Data.StringTypingException Data.TypedDataSetGeneratorException Data.VersionNotFoundException

Data.SqlClient.SqlException

Generated by a warning or error returned by SQL Server

None

IndexOutofRangeException

Generated by an attempt to access an element of an array using an index that is outside the bounds of the array

None

InvalidCastException

Generated by an invalid casting or explicit conversion

None

IO.IOException

Generated when an I/O error occurs

IO.DirectoryNotFoundException IO.EndOfStreamException IO.FileLoadException IO.FileNotFoundException IO.PathTooLongException

The Try...Catch...Finally code block in Listing 1 attempts to calculate the date and time 25 years from the value provided in the StartDate variable.

   'I hope StartDate contains date/time information.   Dim StartDate As Object    Dim EndDate As Date   Dim intYearsToAdd As Integer = 25   Try     EndDate = _   DateAdd("yyyy", intYearsToAdd, StartDate)   Catch ex As System.ArgumentException     'At least one argument has an invalid value   Catch ex As ArgumentOutOfRangeException     ' EndDate is later than December 31, 9999   Catch ex As InvalidCastException     ' StartDate is not a date/time value   Catch ex As Exception     ' Something unexpected happened   Finally     ' Last code to execute before leaving   End Try

You can handle the exceptions that you might expect from the DateAdd function in the first three Catch blocks. Any unexpected exception can be handled in the last Catch block. Keep in mind that no matter what happens, the Finally block will always be the last code to execute before leaving this Try...Catch...Finally code block.

SQLException Exception
Since a large number of the applications being developed today work with databases, the example code in Listing 2 shows the SQLException exception being used. The code in Listing 2 demonstrates how to use the SQLException object.

In the above code, the two lines that are most likely to fail and are thus most in need of error handling are the mySQLConnection.Open() and mySQLCommand.ExecuteReader() methods.

Constructing Your Own Exceptions
In addition to using the built-in exception types, you can also build your own. All user-defined application exception classes are derived from ApplicationException, unlike the built-in common language runtime exception classes derived from SystemException.

Let's take a look at a user-defined Exception class.

   Public Class NotEnoughPizzaException       Inherits System.ApplicationException       Public Sub New()       End Sub       Public Sub New(ByVal strMessage As String)           MyBase.New(strMessage)       End Sub   End Class

As you can see, the new Exception class is based on System.ApplicationException. I added a second overloading New method in order to pass in to the exception what to do about the problem.

   Try     Throw New NotEnoughPizzaException(_          "Better order more")   Catch ex As NotEnoughPizzaException     Response.Write(ex.Message)   End Try

The above code uses the Throw command, which manually throws an exception for the appropriate Catch statement to process.

Working with Unhandled Errors
So far you've used VB.NET to handle potential problems that may arise in the application. What about errors that pop up due to unforeseen circumstances and could not be planned for in your code, such as an invalid URL?

There are three places in ASP.NET that determine how unhandled errors are managed and responded to. Listed in the order in which they occur, the three places are:

  1. In the Page_Error procedure on the ASPX page itself
  2. In Application_Error procedure in the global.asax file
  3. In the customError section of the web.config file.

Page-level Exception Handling
Your first option for dealing with an unhandled error happens at the page level. There are two functions you can use to manage the error:

   Private Sub Page_Error(ByVal sender As Object,    ByVal e As System.EventArgs) Handles MyBase.Error   End Sub

Or

   Protected Overrides Sub OnError(ByVal e As       System.EventArgs)   End Sub

Handling errors in these procedures is simple. A call to Server.GetLastError will return the most recent error. You could also redirect the user to a specific page with Response.Redirect ("MyErrorPage.aspx") or whatever your default error page may be. While it will not be the most common way you will handle errors, the page-level technique for handling errors has its merits.

  • You may need to override the Application_Error or the customErrors setup in the web.config file (more on this later).
  • You can process the error here and if you want to cancel the error processing, so it doesn't go to the Application_Error or customErrors levels, a call to Server.ClearError will do the trick.

Application-Level Exception Handling
Along with page level error handlers, ASP.NET gives developers the ability to provide application-level error handling. This next section will explain how to add application-level exception handling to your ASP.NET applications.

The global.asax File
After the page level error handling, the global.asax file provides the next opportunity to defend against errors.

The global.asax file, also known as the ASP.NET application file, resides in the root directory of an ASP.NET application and is an optional file that contains code for responding to application-level events.

Since the global.asax file is optional, if you do not use one, ASP.NET assumes that you have not defined any application or session event handlers. Visual Studio .NET automatically creates a global.asax when you create a new ASP.NET project.

When an error occurs in your application, ASP.NET executes the Application_Error procedure. This is a great place to track and log errors because it is the most functional place to do so. Odds are that during your ASP.NET development you will find that you will not handle too many errors at the page level. Instead you will opt to handle them at the application level.

As stated before, since the page-level error handling comes first, after ASP.NET calls the Page_Error procedure, then ASP.NET calls the Application_Error procedure. There are a number of things you can do here including e-mailing the system administrator, logging the error to the Windows Event Log, and/or redirect the user to another page with Response.Redirect().

E-mailing the System Administrator
The code in Listing 3 is from the global.asax file. I've removed a number of methods for the sake of space and clarity. I've coded the Application_Error method to send an e-mail containing information about the most recent error.

One thing to note about the code above is that I've added System.Web.Mail to provide SMTP e-mail capability to the Application_Error method.

Logging Errors to the Windows Event Log
The code in Listing 4 is also from the global.asax file. I've added the ability to write information about the current error to the Windows Event Log to the Application_Error method.

Listing 4 expands on the Listing 3 version of the Application_Error method to include writing a record to the event log. If an event log entry does not exist for the entry, one is created before the new entry is added.

The web.config File
ASP.NET provides support for an application configuration file called web.config. ASP.NET lets you use the element of the web.config file as your last chance to gracefully manage an unhandled error since the other two error handlers mentioned so far, Application_Error and Page_Error (or OnError), will get called before customErrors is utilized.

Open up the web.config file for your project and scan down until you find the section. It looks like this:

      

The mode attribute plays a key role in how ASP.NET handles custom errors. Table 3 lists the possible settings and their effect.

Table 3: The customErrors mode settings

Setting

Description

On

Specifies that custom errors are enabled. If there is no defaultRedirect specified the user sees a generic error.

Off

Specifies that custom errors are disabled.

RemoteOnly

Specifies that custom errors are shown only to remote users. ASP.NET errors will display in the user is located on the local host. RemoteOnly is the default setting.

The following will display a generic error page to the user.

   

In the event an unhandled error such as a Response.Redirect("FakePage.aspx") occurs, the user would see a page similar to Figure 1.


Figure 1: The results of an unhandled error with mode = On without a redirected page to display
?
Figure 2: The results of an unhandled error with mode = On with a redirected page to display.

To redirect the user to another page you would change it to this:

   

The same Response.Redirect("FakePage.aspx") line would now result in the user seeing an error page (see Figure 2).

Using the error clause you can also handle specific errors and redirect the user to the error page for each error.

                     

See, that wasn't all that tough, was it? By using a combination of language features like Try...Catch...Finally and exception objects, as well as understanding the built in error handling mechanisms in ASP.NET, there is no reason why your next ASP.NET application shouldn't be ready to take on the obstacles and errors thrown at it on a daily basis.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist