Wiki

Clone wiki

CodeCop / Interceptors

Interceptors

An Interceptor is a class that is used to decorate one method call with additional tasks, e.g. logging, auditing or any other you might want.

To create a new Interceptor, just add a new class to your project and make it implement the ICopIntercept interface.

#!c#

 public class LoggingInterceptor : ICopIntercept
 {
    public void OnBeforeExecute(InterceptionContext context)
    {
      // Code in here will run before the method executes 
    }

    public void OnAfterExecute(InterceptionContext context)
    {
      // Code in here will run after the method executes
    }   
 }

Whenever you want code to be executed before the intercepted method runs you place your code on the OnBeforeExecute method:

#!c#

public void OnBeforeExecute(InterceptionContext context)
{
   Console.WriteLine("Before");
}

On the other hand, if you want code to execute after the intercepted method runs, you place your code on the OnAfterExecute method:

#!c#

public void OnAfterExecute(InterceptionContext context)
{
   Console.WriteLine("After");
}

Override

You have also the option to run code that surrogates the method logic completely. For that to happen, make your interceptor also implement the ICopOverride interface and place your code on the OnOverride method. By convention an intercepted method can only have one override (with the exception when you use the fluent API where you can have as many as you want). If more than one override is found for the same method, the runtime will throw an exception.

#!c#


 public class LoggingInterceptor : ICopIntercept, ICopOverride
 {
    public void OnBeforeExecute(InterceptionContext context)
    {
     // Code in here will run before the method executes
    }

    public void OnAfterExecute(InterceptionContext context)
    {
     // Code in here will run after the method executes
    }

    // This example shows method surrogation. Instead of running the intercepted method original code  we will call BarMethod from the same class 
    public object OnOverride(InterceptionContext context)
    {
      return context.Sender.BarMethod();
    }


 }

Even when we Override the method it is still possible to let the original method code to run. To do so, call the Execute() extension method.

#!c#
public object OnOverride(InterceptionContext context)
{
   public object OnOverride(InterceptionContext context)
        {
            object result = null;

            try
            {
                // Still execute the method 
                result = context.InterceptedMethod.Execute(context.Sender, context.Parameters.Select(x => x.Value).ToArray());
                            }
            catch (Exception)
            {

            }

            return result;
        }
}
NOTE: As CodeCop uses no proxies, calling Execute() restores the method bytes to their original version before execution takes place and to the intercepted version afterwards, so this operation is not guaranteed to be thread-safe. Just make sure for multi-threaded environments you use synchronization mechanisms on the calling clients.

Error Handling

If you want to automatically add exception code and handle errors when interception occurs, you should implement on your interceptor the ICopErrorHandle interface.

Like override there can only be one error handler per intercepted method. If more than one is found, an exception will be thrown.

#!c#

 // Error Handle without override
 public class LoggingInterceptor : ICopIntercept, ICopErrorHandle
 {
    public void OnBeforeExecute(InterceptionContext context)
    {
     // Code in here will run before the method executes
    }

    public void OnAfterExecute(InterceptionContext context)
    {
     // Code in here will run after the method executes
    }

     public void OnError(InterceptionContext context)
     {
       Console.WriteLine("An exception occured: {0}", context.Exception.Message");
     }


 }
#!c#

 // Error Handle with override
 public class LoggingInterceptor : ICopIntercept, ICopOverride, ICopErrorHandle
 {
    public void OnBeforeExecute(InterceptionContext context)
    {
     // Code in here will run before the method executes
    }

    public void OnAfterExecute(InterceptionContext context)
    {
     // Code in here will run after the method executes
    }

     public object OnOverride(InterceptionContext context)
     {
       return context.Sender.BarMethod();
     }

     public void OnError(InterceptionContext context)
     {
       Console.WriteLine("An exception occured: {0}", context.Exception.Message");
     }


 }

InterceptionContext

Whenever you intercept a method you receive as parameter on your interceptor an InterceptionContext object. That object has the following properties :

  • Sender - The current class instance that called the intercepted method.
  • InterceptedMethod - A MethodBase object that represents the intercepted method.
  • Parameters - An array of Parameter objects that represent the parameters passed to the method at the moment of execution.
  • GenericArguments - An array that contains all the generic arguments that were used to create a closed generic instance of the intercepted method.
  • Timestamp - A DateTime object that contains the date and time when the interception callback took place.
  • Exception - If an exception occurs while executing or overriding the method and you have implemented ICopErrorHandle on an interceptor, this property contains the exception itself.
  • TransferBag - A generic dictionary to pass custom objects or state between interception phases.
#!c#
public void OnBeforeExecute(InterceptionContext context)
{
    Console.WriteLine("Method {0} has been called at {1}", context.InterceptedMethod.Name, context.TimeStamp.ToString());
}

Updated