Custom Exceptions in VB 2005

Structured exception handling was introduced to Visual Basic programmers with the first .NET version of the language. Structured exception handling is important for two reasons:

  1. It simply makes code more readable by using a syntax that is more congruent with the rest of the language compared to the old On Error Goto... statement.
  2. It is much more powerful than the On Error Goto... statement and provides a greater level of flexibility and control.

Catching and Throwing Exceptions

Exception handling is implemented with the Try...Catch...Finally...End Try statement. The basic syntax looks like this:

Try
   ' Code that could raise an exception.
Catch
   ' Code to handle the exception.
Finally
   ' Code to cleanup (close database connections, etc.).
End Try

The Try and End Try statements are both required. The Catch and Finally statements may both be used in a Try block, but at least one of them is required. Also, multiple Catch statements are allowed to handle different types of exceptions. If you have multiple Catch blocks, order them from the most specific type of exception to the least specific:

Try
   ' Code that could raise an exception.
Catch ex As ArgumentOutOfRangeException
   ' Handle an invalid argument possibly using a default
   ' value so the code can continue
Catch ex As Exception
   ' Handle any other type of exception
Finally
   ' Code to cleanup (close database connections, etc.).
End Try

You also can throw exceptions in your code. This is useful when you catch an exception in part of your code, perform some cleanup code, and then throw the exception so a higher-level procedure can catch it. Throwing exceptions is also useful when creating custom exception types.

To throw an exception, you would write something like this:

Throw New ArgumentOutOfRangeException

ArgumentOutOfRangeException tells the Throw statement what type of exception to throw. The ArgumentOutOfRangeException type is just one of the many that the .NET Framework provides.

Propagating Exceptions

When an exception occurs somewhere in your code, you can propagate it in three ways:

  • Do nothing and let it propagate back up the call stack automatically.
  • Catch it and re-throw it. This allows you to run some cleanup code in the Finally block.
  • Catch it, wrap the exception in another exception using the InnerException property, and throw the new exception back to the calling procedure. The InnerException property lets you maintain the original exception and its information inside a more relevant exception.

Introducing Custom Exceptions

Although the .NET Framework provides many standard exceptions, you also can create, throw, and catch your own custom exceptions. In general, Microsoft recommends that you use the standard exceptions provided by the .NET Framework. However, if your application has a need that a standard exception does not satisfy, you can create a custom exception.

When you create a custom exception type, you gain control of all of the exceptions properties. You also can add properties to your custom exception class. This gives you a place to store crucial pieces of data besides embedding them in the Message property. This makes retrieval of the crucial data simple without parsing them out of the Message property.

Custom Exception Sample Application

To understand custom exceptions, create a very simple command line application. You can download all of the code and necessary files from the link at the end of the article.

The code package includes a very simple MS Access database that contains one table, named Customer. Not surprisingly, the Customer table contains a list of customers with ID, first name, last name, and address details. The actual contents of the database are not important, but data access is a good context for your custom exception.

For the application, I created a new console application in the VB 2005 Express IDE.

DatabaseException Base Class

If you're going to have more than one custom exception, it's a good idea to create a custom base class for them. This base class will inherit from the System.Exception class that the .NET Framework provides. It also will contain the three constructors that will be common to all of your custom exceptions. The sample application's base class is called DatabaseException; the code is listed below:

Public Class DatabaseException
   Inherits Exception

   Public Sub New()
   End Sub

   Public Sub New(ByVal message As String)
      MyBase.New(message)
   End Sub

   Public Sub New(ByVal message As String, ByVal inner As Exception)
      MyBase.New(message, inner)
   End Sub
End Class

The three constructors are the standard constructors provided by the System.Exception class. The first allows you to create an exception without using any parameters, just the default exception properties. The second allows you to specify a message string to use as the Message property of your exception. Finally, the third constructor also allows you to specify the message string, but it lets you specify an exception as the second parameter as well. The System.Exception class has a property called InnerException that is useful when you catch an exception and want to wrap it inside a more relevant exception. By setting the InnerException property, you can maintain all of the information in the original exception.

One last note about the base class: There seems to be some disagreement as to whether you should inherit from the System.Exception class or the System.ApplicationExeption class. Most of the older literature from Microsoft states you should inherit from System.ApplicationException, but the new philosophy seems to state that you should instead inherit from the System.Exception class. I'm not sure what, if any, technical differences there are, but I tested with the base class inheriting from each and it works both ways. For the purposes of the sample application, follow the newer philosophy and inherit from System.Exception. Perhaps exploring this difference is fodder for a future article.

Custom Exceptions in VB 2005

Custom Exception: CustomerNotFoundException

The first custom exception class is called CustomerNotFoundException. You will throw this exception when you attempt to look up a customer in your database but do not find a match. The code is listed below:

Public Class CustomerNotFoundException
   Inherits DatabaseException

   Private m_CustomerID As Long

   Public ReadOnly Property CustomerID() As Long
      Get
         Return m_CustomerID
      End Get
   End Property

   Public Sub New(ByVal customerID As Long)
      MyBase.New("Customer ID was not found.")
      m_CustomerID = customerID
   End Sub
End Class

This class inherits from the DatabaseException base class you created earlier. It contains only one constructor, which takes the customerID as a parameter. When this constructor is called, you pass the text string "Customer ID was not found." into the constructor of the base class to be used as the Message property. You also have a readonly property called CustomerID defined. You will use the CustomerID property to store the value of the customer ID that was passed in as a parameter. It is a readonly property because it does not make any sense to change the value to something other than the value that caused the exception.

Custom Exception: DatabaseUnavailableException

The second custom exception class is called DatabaseUnavailableException. You will throw this exception when an exception occurs while you're attempting to connect to the database. The code is listed below:

Public Class DatabaseUnavailableException
   Inherits DatabaseException

   Public Sub New(ByVal ex As Exception)
      MyBase.New("The database is not available.", ex)
   End Sub
End Class

This class is very similar to your CustomerNotFoundException class. You do not have any additional properties defined for this class, but the primary difference is that it takes a System.Exception as a parameter and passes it into the constructor in your base class. This System.Exception parameter will become the InnerException property of your DatabaseUnavailableException.

Customer Class

The Customer class is a simple class that takes a database name and a customer ID as parameters for the constructor and attempts to retrieve the data for that customer. The first thing the constructor does is attempt to connect to the database by using the ConnectDB method as follows:

Private Sub ConnectDB(ByVal database As String, _
                      ByRef cn As OleDbConnection)
   cn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; _
                          Data Source=" & _
                          """" & database & """"

   Try
      cn.Open()
   Catch ex As Exception
      Throw New DatabaseUnavailableException(ex)
   End Try
End Sub

You attempt to open the database connection inside a Try statement. If any exception is thrown, you catch it and throw a DatabaseUnavailableException, wrapping the original exception in its InnerException property.

If you make a successful connection to the database, you then try to retrieve the data for the specified customer ID using the GetCustomer method as follows:

Private Sub GetCustomerData(ByVal cn As OleDbConnection, _
                            ByVal customerID As Long)
   Dim cmd As New OleDbCommand
   Dim reader As OleDbDataReader

   cmd.Connection = cn
   cmd.CommandText = "SELECT * FROM CUSTOMER WHERE ID = " _
                     & customerID

   reader = cmd.ExecuteReader
   If reader.HasRows Then
      reader.Read()
      m_id = reader.Item("ID")
      m_firstname = reader.Item("Firstname")
      m_lastName  = reader.Item("Lastname")
      m_street    = reader.Item("Street")
      m_city      = reader.Item("City")
      m_state     = reader.Item("State")
      m_zipCode   = reader.Item("Zip")
   Else
      Throw New CustomerNotFoundException(customerID)
   End If
End Sub

You execute a SQL query using the customerID to specify which customer's data you want to retrieve. If the query returns a result, you set the properties of the Customer class using the values returned by the query. But, if you do not get any data, you throw a CustomerNotFoundException using the customerID as a parameter for the constructor. This value will be used to set the CustomerID property of your CustomerNotFoundException object.

App in Action

The following screenshots show your application in action. To run the application, call it from a command prompt and specify a database name and customer ID as arguments. The three screen shots show a successful query (see Figure 1), a CustomerNotFoundException being thrown (see Figure 2), and a DatabaseNotAvailableException being thrown (see Figure 3).

[Figure1.jpg]

Figure 1. Successful Query

[Figure2.jpg]

Figure 2. CustomerNotFoundException

[Figure3.jpg]

Figure 3. DatabaseUnavailableException

Wrapping It Up

Custom exception types are a powerful feature of the VB .NET language. The .NET Framework provides many standard exception types that will suffice for most needs. In fact, you may rarely use anything but the standard exceptions, but the ability to create custom exceptions is a powerful tool to have.

About the Author

Josh Fitzgerald is an applications development group leader for a large medical device company in Warsaw, Indiana. Designing and developing Visual Basic .NET applications is only one of his responsibilities, but it is his favorite part of his job. You can reach Josh at josh.fitzgerald@gmail.com.



Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds