<

Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x

DRY Exception Handling with PostSharp

Published on
11,993 Points
8,793 Views
2 Endorsements
Last Modified:
Exception Handling is in the core of any application that is able to dignify its name.
In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.

Aspect Oriented Programming?

So first things first: What is Aspect Oriented Programming (AOP)?

AOP is a coding pattern that allows the developer to isolate repetitive and often technical code from the business logic. It differs from the normal refactoring towards the single responsibility principle. AOP completely removes the code from the visible code-base to be, and instead configurs and "injects" it at compile-time or execution-time depending on the language. Wikipedia does a good job explaining it in much deeper detail.
 

One good example?

One good example is Exception Handling and Logging.

All applications have their own way of handling exceptions, and the complexity greatly depends on the number of systems and modules integrated.

On a SOAP service, for instance, you might end up with a nasty list of try/catch(es) in order to be able to log the exceptions in different categories (Technical, Business, Unhandled) and you need to repeat this logic for every service method. On top of that, it will pollute enormously the code without adding any business value to it; it's just technical code!

Take this example:


public void DoSomething()
{
    try
    {
        // do whatever you need to do
    }
    catch (BusinessException ex)
    {
        // log this with a lower severity
        // create the message to be logged
        // concat the stack trace or whatever good way to document the error
        // call your logging tool of choice /SemanticLogging, Log4Net, NLog, ...)
    }
    catch (TechnicalException ex)
    {
        // log this with a higher severity
        // create the message to be logged
        // concat the stack trace or whatever good way to document the error
        // call your logging tool of choice /SemanticLogging, Log4Net, NLog, ...)
    }
    catch (Exception ex)
    {
        // make all hell brake loose!
        // create the message to be logged
        // concat the stack trace or whatever good way to document the error
        // call your logging tool of choice /SemanticLogging, Log4Net, NLog, ...)
    }
}

Open in new window

image.gifimage.gifThis is just for one method... we need to repeat all of it for all the methods.

Making it DRY

DRY stands for Don't Repeat Yourself, and if you look at the above code, you already see a lot of repetition; adding more methods will only make it worse.

Wouldn't it be nice if you could simply write


public void DoSomething()
{
  // do whatever you need to do
}

Open in new window

image.gifimage.gif and still be able to handle the exceptions in the same way but behind the scenes?


PostSharp to the rescue

PostSharp is a free tool that implements AOP on the .Net Framework. By free, I mean free as free beer... there's no catch here. Although they have commercial versions, the Express edition is fully functional, supported and the is base of their commercial products. You can also use it for commercial purposes and so on. I recommend reading their FAQ and compare their editions.

With PostSharp we can have something like:


[MyExceptionHandler]
public void DoSomething()
{
  // do whatever you need to do
}

Open in new window

image.gifimage.gif or even better, applied to all the methods within the class:



[MyExceptionHandler]
public class MyClass
{
  public void DoSomething()
  {
    // do whatever you need to do
  }
}

Open in new window

image.gifimage.gifimage.gif

But what is that MyExceptionHandler attribute?

It's a custom attribute that looks like this:


[Serializable]
public class MyExceptionHandlerAttribute : OnExceptionAspect
{
  public MyExceptionHandlerAttribute (){ }

  public override void OnException(MethodExecutionArgs args)
  {
    if (args.Exception.GetType().Equals(typeof(BusinessException)))
    {
       if (args.Exception.InnerException == null)
         MyEventSource.Log.BusinessError(args.Exception.Message);
       else
       {
         var message = args.Exception.Message;
         var extraInfo = args.Exception.InnerException.ToString();

         MyEventSource.Log.BusinessError(message, extraInfo);
       }
    }
    else if (args.Exception.GetType().Equals(typeof(TechnicalException)))
    {
      var message = args.Exception.Message;
      var extraInfo = args.Exception.InnerException?.ToString();
      var stackTrace = args.Exception.StackTrace;

      MyEventSource.Log.TechnicalError(message, extraInfo, stackTrace);
    }
    else
    {
       var message = args.Exception.Message;
       var extraInfo = args.Exception.InnerException?.Message;

       MyEventSource.Log.UnhandledError(message, extraInfo);
    }


    /*
    USE THIS IF YOU DON'T WANT TO RETHROW THE EXCEPTION.
    LIKE THIS YOU LOG THE ERROR AND THE APPLICATION WON'T COMPLAIN.

    IF THIS IS FOR A WEB APP, YOU CAN CONSIDER NOTIFYING THE USER OR 
      REDIRECTING TO AN ERROR PAGE */
    args.FlowBehavior = FlowBehavior.Continue;
  }

}

Open in new window


The OnExceptionAspect aspect

OnExceptionAspect is what tells PostSharp to do its magic behind the scenes, and very importantly, at compile time. PostSharp will wrap the contents of the method that has this attribute with a try/catch block, so this has nothing to do with runtime Reflection and won't impact the performance of your application.

OnExceptionAspect has only one method to override that is the OnException:


public override void OnException(MethodExecutionArgs args)
{
  // handle the exception
}

Open in new window

The single argument, MethodExecutionArgs, has all the information you need in order to decide what to do with the exception. Have a look at the documentation for a complete reference.

You might also wonder what's that MyEventSource there, right?

At that point, it really depends on what kind of logging mechanism you want to use. Personally, I like SemanticLogging, but Log4Net and NLog are also really good options. The logging tool implementation itself, as it can be anything you want, is out of the scope of this article. I might write about them in separate articles.

So my implementation, for SemanticLogging, is the following:


[EventSource(Name = "MyApp")]
public class MyEventSource : EventSource
{
  public class Keywords
  {
    public const EventKeywords Page = (EventKeywords)1;
    public const EventKeywords DataBase = (EventKeywords)2;
    public const EventKeywords Diagnostic = (EventKeywords)4;
    public const EventKeywords Perf = (EventKeywords)8;
  }

  public class Tasks
  {
    public const EventTask Page = (EventTask)1;
    public const EventTask DBQuery = (EventTask)2;
  }

  private static MyEventSource _log = new MyEventSource();
  private MyEventSource() { }
  public static MyEventSource Log { get { return _log; } }

  [Event(500, Message = "Unhandled Error: {0}. Extra Info: {1}", Level = EventLevel.Critical, Keywords = Keywords.Diagnostic)]
  internal void UnhandledError(string message, string extraInfo)
  {
    if (this.IsEnabled())
      this.WriteEvent(500, message ?? "", extraInfo ?? "");
  }

  [Event(501, Message = "Application Technical Error: {0}. Extra Info: {1}. StackTrace: {2}", Level = EventLevel.Critical, Keywords = Keywords.Diagnostic)]
  internal void TechnicalError(string message, string extraInfo, string stackTrace)
  {
    if (this.IsEnabled())
      this.WriteEvent(501, message ?? "", extraInfo ?? "", stackTrace ?? "");
  }

  [Event(400, Message = "Application Business Error: {0}. Extra Info: {1}", Level = EventLevel.Critical, Keywords = Keywords.Diagnostic)]
  internal void BusinessError(string message, string extraInfo = null)
  {
    if (this.IsEnabled())
      this.WriteEvent(400, message ?? "", extraInfo ?? "");
  }

  [Event(200, Message = "{0}", Level = EventLevel.Informational)]
  public void Information(string message)
  {
    if (this.IsEnabled()) this.WriteEvent(200, message ?? "");
  }

} 

Open in new window


What else can you do?

Well, at this point you got the AOP idea, and the OnExceptionAspect is only one of many aspects PostSharp supports. PostSharp documentation does a really awesome job describing not only PostSharp itself but also the whole AOP concept.

Make sure you have a good look at it: Documentation.
2
Comment
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
0 Comments

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Join & Write a Comment

This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Is your data getting by on basic protection measures? In today’s climate of debilitating malware and ransomware—like WannaCry—that may not be enough. You need to establish more than basics, like a recovery plan that protects both data and endpoints.…

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month