Troubleshooting Tips and Tricks
LANGUAGES: VB .NET
TECHNOLOGIES: Custom Exceptions | Serialization
Serialize Custom Exceptions
Learn what to do when .NET's built-in exception classes just don't cut it.
By Don Kiely
In an upcoming article for asp.netPRO magazine, I cover creating and using custom exception classes you can use when the built-in .NET exception classes simply aren't enough. Custom exceptions come in handy when none of the .NET exception classes describe what went wrong, or if you want to add additional information about the problem beyond a simple message string.
The base exception class, System.Exception, includes four constructors, any or all of which you can override in your custom exception class. Depending on how you'll use the custom exception, normally you always override the first three:
- The default constructor that takes no parameters and simply calls the base class's constructor
- A constructor that takes a string parameter to include a custom message string
- A constructor that takes a custom message string and another exception object that you then can access through the custom exception's InnerException property
The fourth constructor, serialization, is optional, but it's required if you are going to support serialization. Serialization lets you take an object and convert it to a stream of bytes that are useful for streaming to a disk file, converting to XML, or passing as an array of bytes to another component. The underlying exception objects are serializable already, but you must provide support for any custom properties you implement as part of the custom exception.
In the scenario I used for the code, the custom aspnetPROException class carried along with it information about the application, the environment in which it was running, and some contact information for the developer. By including this information and providing support for serializing the exception, you can stream the object directly to some store - such as the Windows event log - and all information is carried along in a complete unit. Doing things this way means you don't have to add additional info to the event log programmatically; you simply stream it there and the developer has all the information needed to resolve the problem.
Here's how the serialization constructor looks. This constructor takes two parameters, SerializationInfo and StreamingContext objects that .NET passes to the constructor automatically. Both are part of the System.Runtime.Serialization namespace in the .NET Framework:
Protected Sub New(ByVal info As SerializationInfo, _
ByVal context As StreamingContext)
'Probably won't be used much, but this constructor accepts
'serialized data to rehydrate an exception object
msAppName = info.GetString("msAppName")
msPlainDesc = info.GetString("msPlainDesc")
msDevEmail = info.GetString("msDevEmail")
msDevPhone = info.GetString("msDevPhone")
mdOccurred = info.GetDateTime("mdOccurred")
msMachineName = info.GetString("msMachineName")
msAppDomain = info.GetString("msAppDomain")
This version of the constructor starts by calling the constructor of the underlying base class, just like the other constructors. The parameters passed into this constructor are info and context. info provides information about the interface members of the class - those that need to be serialized or deserialized. context describes the source and destination of the serialization stream.
The rest of the code in the constructor links the class's private variables to how they are serialized. Each line reads the value of a key from the serialized data and assigns that value to the appropriate module variable. This is how the custom properties of the custom exception are "rehydrated."
The flip side of this serialization constructor is the GetObjectData method. To serialize an object's data properly, you need to override this method of the base class and write the values of your custom properties:
Public Overrides Sub GetObjectData(ByVal info As SerializationInfo, _
ByVal context As StreamingContext)
info.AddValue("msAppName", msAppName, GetType(String))
info.AddValue("msPlainDesc", msPlainDesc, GetType(String))
info.AddValue("msDevEmail", msDevEmail, GetType(String))
info.AddValue("msDevPhone", msDevPhone, GetType(String))
info.AddValue("mdOccurred", mdOccurred, GetType(Date))
info.AddValue("msMachineName", msMachineName, GetType(String))
info.AddValue("msAppDomain", msAppDomain, GetType(String))
This code adds the value of each custom property in turn, identifying the type of data with GetType. The last line of code calls the base class's GetObjectData method, passing in the info object that now contains both the standard properties of an exception object and our custom properties.
By overriding the serialization constructor and the GetObjectData method of the base System.Exception class, you can serialize your custom exception object to almost any kind of data store. And you can take advantage of all the serialization support in .NET to handle any kind of data, including binary data.
Don Kiely is senior technology consultant for Information Insights, a business and technology consultancy in Fairbanks, Alaska. E-mail him at mailto:[email protected].