Saturday, December 31, 2011

- Exception Handling

Structured Exception Handling (SEH):
SEH is a technique for dealing with runtime exceptions. Let's go through some terminology first:
  • Bugs: error made by the programmer
  • User errors: error caused by individuals running your application
  • Exceptions: runtime anomalies
SEH have the following advantages:
  • unified approach
  • can throw SOAP fault to a remote caller
  • contains human readable description
SEH involves the use of four interrelated entities:
  • Class type  represent the details of the exception
  • Member that throws an instance of the exception class to the caller 
  • Exception-prone  member in caller's side
  • Catch in caller's side
System.Exception:
Consider the important methods and property of Exception class at below. As you see many of the properties are read-only in nature, since derived types will typically supply default values for each property.

public class Exception : ISerializable, _Exception
{
    //public constructors
    public Exception();
    public Exception(string message);
    public Exception(string message, Exception innerException);

    //public properties
    public virtual IDictionary Data { get; }
    public virtual string HelpLink { get; set; }
    public Exception InnerException { get; }
    public virtual string Message { get; }
    public virtual string Source { get; set; }
    public virtual string StackTrace { get; }
    public MethodBase TargetSite { get; }

    //public methods
    public virtual Exception GetBaseException();
     public virtual void GetObjectData(SerializationInfo info, StreamingContext context);
    public Type GetType();
}

Note that  _Exception interface allows a .NET exception to be processed by an unmanaged code base and the ISerializable interface allows an exception object to be persisted across boundaries. 
Here is the description of Exception type properties:
  • Data: retrieve a collection of key/value pairs which provides additional programmer defined information about the exception (read only). the collection by default is empty.
  • HelpLink: URL to help file or website 
  • InnerException: it used in order to get information about the previous exception(s) that caused the current exception to occur.(read only)
  • Message: returns textual description of a given error.(set as constructor parameter)
  • Source: name of the assembly or the object which threw the current exception.
  • StackTrace: a string which contains a sequence of calls that triggered the exception. (read only)
  • TargetSite: returns a MethodBase object, which describes numerous details about the method that threw the exception.
C# throw keyword is used to send the exception object back to the caller. Consider the below example:
Non debug mode: (start without debugging)
Unhandled exception(release mode)

Debug mode:
Unhandled exception(Debug mode)
As you see in above screenshot after invoking the ThrowExceptionSample this message show up since I didn't catch the exception in caller object. A block of try/catch is feed our requirement in order to catch the exception. Example:

try
{
    myObject.ThrowExceptionSample();
}
catch (Exception e)
{
    Console.WriteLine("Mehod: {0}", e.TargetSite);
    Console.WriteLine("Message: {0}", e.Message);
    Console.WriteLine("Source: {0}", e.Source);
}
try/catch output

TargetSite:
TargetSite returns strongly typed System.Reflection.MethodBase object, that contains useful information about the method as well as the class which threw the exception, such as:
  • MethodBase.DeclaringType: return the fully qualified name of the class
  • MethodBase.MemberType: identify the type of member (method / property)
Let's go through another example with more details:
    //sample method to send an exception
    public void ThrowExceptionSample()
    {
        //create local variable in order to initialize some properties and methods
        Exception ex = new Exception("this method shows how to throw an exception");
               
        ex.HelpLink = "http://mehdicsharpblog.blogspot.com/";
               
        ex.Data.Add("TimeStamp", string.Format("exception occured at {0}",DateTime.Now));
        ex.Data.Add("Cause", "Just for demonstration");

        throw ex;
    }
    Here is the try/catch block:
    //try/catch block in the caller
    try
    {
        myObject.ThrowExceptionSample();
    }
    catch (Exception e)
    {
        Console.WriteLine("Mehod: {0}", e.TargetSite);
        Console.WriteLine("Class defining member: {0}", e.TargetSite.DeclaringType);
        Console.WriteLine("Member Type: {0}", e.TargetSite.MemberType);
        Console.WriteLine("Message: {0}", e.Message);
        Console.WriteLine("Source: {0}", e.Source);
        Console.WriteLine("Help Link: {0}", e.HelpLink);
        if (e.Data != null)
        {
            Console.WriteLine("Data:");
            foreach (DictionaryEntry item in e.Data)
                Console.WriteLine("-> {0}: {1}", item.Key, item.Value);
        } 
    }
      Exception example output
       The following types drives from Exception type, which they are helpful to identify the source of the exception.
      • System-Level Exception : exceptions that are thrown by the .NET platform (aka non-recoverable, fatal errors) which are derived from System.SystemException, which in turn derives from System.Exception.
      • Application-Level Exception : it is good practice to extend your custom exception from System.ApplicationException to identify code base executing application
      Above derived types do not define any additional members beyond a set of constructors.
      It is a good practice to use following exception for incomplete methods as it does Visual Studio on your behalf when you use auto completion features:

      throw new NotImplementedException(); 

      Custom Exception:
      It is good practice to build a strongly typed exception that represents the unique details of your current problem. Custom exception can be derived directly from System.Exception or from System.ApplicationException. it is always better to mark the exception class as public, cause exceptions are often passed outside of assembly boundaries. As an example we create a exception class for shape class:

      [Serializable]
      public class ShapeSampleException : ApplicationException
      {
          public DateTime TimeStamp { get; set; }
          public string Cause { get; set; }

          //constructors:
          //default
          public ShapeSampleException() { }
          //set the inherited message property
          public ShapeSampleException(string msg)
              : base(msg) { }
          //handel inner exception
          public ShapeSampleException(string msg, Exception inner)
              : base(msg, inner) { }
          public ShapeSampleException(SerializationInfo info, StreamingContext context)
              : base(info, context) { }
          //custom
          public ShapeSampleException(string msg, string cause, DateTime time)
              :base(msg)
          {
              Cause = cause;
              TimeStamp = time;
          }
      }

      By adding above custom exception class we our throw exception block become like this:

      public void ThrowExceptionSample()
      {
          ShapeSampleException ex = new ShapeSampleException("this method shows how to throw an exception",
              "Just for demonstration", DateTime.Now);
                 
          ex.HelpLink = "http://mehdicsharpblog.blogspot.com/";
          throw ex;
      }
      And here is the new try/catch block:

      try
      {
          myObject.ThrowExceptionSample();
      }
      catch (ShapeSampleException e)
      {
          Console.WriteLine(e.Message);
          Console.WriteLine(e.TimeStamp);
          Console.WriteLine(e.Cause);
      }
      ShapeSampleException class diagram (inheritance)
      Custom exceptions are usually needed when the error is tightly bound to the class issuing the error. Good to know Visual Studio 2010 provides code snippet template for exception as well. When the intelligent shows the following:
      exception snippets template
      By pressing Tab key two times following code will be generate for you and you may easily customize it;
      [Serializable]
      public class MyException : Exception
      {
          public MyException() { }
          public MyException(string message) : base(message) { }
          public MyException(string message, Exception inner) : base(message, inner) { }
          protected MyException(
            System.Runtime.Serialization.SerializationInfo info,
            System.Runtime.Serialization.StreamingContext context)
              : base(info, context) { }
      }
      It might occur one try block trigger numerous possible exceptions, in these cases we can use multiple catch block. Exception will proceed by the first match exception, that's why it is always better to start with most specific exception.
      C# provides a way to handle all errors in very general way by leave the catch block without any parenthesis and arguments.

      catch
      {
          //catch any kind of exception
      }

      You can rethrow the exception to the caller by throw keyword. Pay attention throw will rethrow the original exception object.

      Inner Exceptions:
      If you encounter an exception while processing another exception, you need to record the new exception object as an "inner exception" within a new object of the same type as the initial exception, which is only useful when the caller has the ability to gracefully catch the exception in the first place.

      catch (ShapeSampleException exception)
      {
          try
          {
              //let's say another exception will occur here
          }
          catch (Exception inner_excpetion)
          {
              //Throw an exception that records the new exception,
              //as well as the message of the first exception
              throw new ShapeSampleException(exception.Message, inner_excpetion);
          }
      }

      Finally Block:
      This is a optional block after try/catch block, to make sure a set of code statements will always execute, with or without exception. It is very useful for dispose of objects, close a file or detach from a database.

      In order to see exceptions thrown by a base class library member you may refer to .NET framework 4.0 SDK documentation or simply hovering your mouse cursor over the member name:
      exceptions thrown by a base class library
      In debug mode if any unhandled exception occurs you may get more details if you click on View Details... here is an example:
      View Details of Exception

      Corrupted State Exception (CSE):
      .NET 4.0 have introduced new name space ExceptionServices under mscorlib as you can see in below snapshot. This namespace helps you to equip various methods within your application with the ability to intercept and process CSE.
      Object Browser fro Exception Services

      As you know .NET platform sits on top of the hosting operating system. Within the windows API, it is possible to trap extremely low-level errors (CSE).
      Before .NET 4.0 the CLR would allow these very low-level OS-specific errors to be trapped using general System.Exception catch block, however .NET platform does not provide much by way of elegant recovery code. Now for .NET 4.0 you need to import the System.Runtime.ExceptionServices namespace and add the [HandledProcessCorruptedStateException] attribute in order to trap low-level OS errors within catch block .


      Reference: Pro C# 2010 and the .NET 4 Platform by Andrew Troelsen.

      No comments:

      Post a Comment