posted on Saturday, January 10, 2004 1:18 PM by taylorza

Boilerplate Code - Exception Classes

Continuing with my boilerplate series, I will present the template that I use when defining an exception hierarchy. This template addresses not only the requirements of the design guidelines for class library developers, but also ensures that the exception can be passed across remoting boundaries. In a later blog I will address the issues particular to the remoting scenario.

First from the guidelines we know that we need to derive our exceptions from either ApplicationException or SystemException branches, yet in my experience it is still very common to see exception classes derived directly from the Exception class. Additionally the class must provide the following four constructors.

public CustomException()
public CustomException(string message)
public CustomException(string message, Exception inner)
public CustomException(SerializationInfo info, StreamingContext context)

This will be enough to have an exception class that conforms to the guidelines, however an exception that includes any additional information and stricly conforms to this will not be successfully passed across remoting boundaries. To ensure that the exception is remotable you also need to implement the ISerializable interface, this is partially addressed by the provision of the de-serialization constructor, but that only caters for de-serialization, to complete the picture you will also require an implementation of GetObjectData to assist with the serialization of the exception. At first you might wonder why just marking an exception with SerializableAttribute will not suffice, but carefull inspection reveals that the Exception class already implements ISerializable therefore we have to provide a customized implemetation of the ISerializable methods. Without further delay I will present the template and a sample implementation.

[Serializable]
public class TemplateException : ApplicationException
{
  public TemplateException()
  {
  }
  public TemplateException( string message ) :
    base ( message )
  {
  }
  public TemplateException( string message, Exception inner ) :
    base ( message, inner )
  {
  }
  public TemplateException( SerializationInfo info, StreamingContext context ) :
    base( info, context )
  {
  }
  public override void GetObjectData( SerializationInfo info, StreamingContext context )
  {
    base.GetObjectData(info, context);
  }
}

The following is an implementation of the above template, it is not really usefull other than to clarify the actual implementation of the serialization methods. Using the above template as a guide the following would define a custom exception called not very imaginatively CustomException. This implementation assumes that at least the custom information must be provided therefore there is no default constructor.

[Serializable]
public class CustomException : ApplicationException
{
  private const string _customInfoKey = "CustomInfo";

  private string _customInfo; 

  public CustomException ( string customInfo )
  {
    _customInfo = customInfo;
  }

  public CustomException ( string message, string customInfo ) :
    base ( message )
  {
    _customInfo = customInfo; 
  }

  public CustomException (string message, string customInfo, Exception inner) :
    base ( message, inner )
  {
    _customInfo = customInfo;
  }

  public CustomException (SerializationInfo info, StreamingContext context) :
    base( info, context )
  {
    _customInfo = info.GetString( _customInfoKey );
  }

  public override void GetObjectData( SerializationInfo info, StreamingContext context )
  {
    base.GetObjectData(info, context); 
    
    info.AddValue( _customInfoKey, _customInfo );
  }

  public string CustomInfo
  {
    get { return _customInfo; }
  }
}

In a future post I will certainly address some of the finer points required to pass this exception using the .NET remoting infrastructure, but those are details specific to .NET remoting and do not affect the above template in any way.

Comments