Sunday, March 10, 2013

Aspect Oriented Programming: Logging and Handling Exception using PostSharp


Today, I am going to explain on how to do logging and exception handling in aspect oriented programming using PostSharp. Suppose, if you want to find the execution time of each function, usually we would create two datetime variable, get the time at start and end of the method and find the difference at the end which would give execution time of method/function.
       
         In ASP.Net MVC, we can easily to do for controller actions by creating custom ActionFilterAttribute and overriding OnActionExecuting and OnActionExecuted methods. Same way, if you want to do for library class methods, you have to manually write code for each methods at start and end of the method. If we have to do for more no. of functions in library, its difficult to write code for each function which it turn difficult to manage.
      
       Traditionally, If you want to handle the exception and log the exception, you would use try catch block and handle the exception in catch block and log the error; and re-throw it again if needed. 

Aspect Oriented Programming (AOP):
      To handle the above situation easily, we can use aspect oriented programming (AOP). AOP can be implemented using several third party components like PostSharp, Sprint.Net AOP, etc. Here, I'm going to explain using PostSharp.

Requirements:
1. Log information at start and end of each method/function in class without writing code for each method in class.
2. Log error if function throws any error without writing exception logging in catch block of each method.

To experiment the above requirements, follow the below steps .

1. Install Postsharp from NuGet Packages.



2. For Logging, create a class Logger (You can name it whatever you want) and inherit the OnMethodBoundaryAspect class. Then overrride OnEntry and OnExit method to log the information like below.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PostSharp.Aspects;

namespace AOPSampleApp.Aspects
{
    [Serializable]
    public class Logger : OnMethodBoundaryAspect
    {
        public override void OnEntry(MethodExecutionArgs args)
        {
            //TODO Enter Logging.
            // Start the stop watch
            base.OnEntry(args);
        }

        public override void OnExit(MethodExecutionArgs args)
        {
            //TODO Exit Logging
            // stop the stop watch
            base.OnExit(args);
        }
    }
}

3. For Exception Handling, create a class ExceptionHandler (You can name it whatever you want) and inherit the OnExceptionAspect class. Then overrride OnException method to log the error like below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PostSharp.Aspects;

namespace AOPSampleApp.Aspects
{
    [Serializable]
    public class ExceptionHandler : OnExceptionAspect
    {
        public override void OnException(MethodExecutionArgs args)
        {
            //TODO Exception Logging
            args.FlowBehavior = FlowBehavior.Continue;

            base.OnException(args);
        }
    }
}

4. Add above class (Logger and ExceptionHandler) as an attribute to any method where you want to handle the logging  at start, end of the method or handle the exception like below.

class Program
    {
        static void Main(string[] args)
        {
            Add();
            Divide();
        }

        [Logger]
        static void Add()
        {
            int a = 1, b = 2, c;
            c = a + b;
        }

        [ExceptionHandler]
        [Logger]
        static void Divide()
        {
            int a = 1, b = 0, c;
            c = a / b; // Dividing by Zero
        }


    }


Order of Execution for Above Code:

1. Call Add Method.
2. Execute OnEntry method of Logger before initialize a,b,c and calculate sum.
3. Execute the Add method.
4. Execute OnExit method of logger after completing the execution of Add method.
5. Call Divide Method.
6. Execute OnEntry method of Logger before before throwing exception in Divide method.
3. Execute the Divide method and throw an exception.
4. Execute OnException method of ExceptionHandler.
4. Execute OnExit method of logger after completing the execution of Divide method.
 
From the above, you could understand that we can easily handle the logging and exception using Postsharp.



No comments: