Aspect-oriented programming (AOP) with Spring.NET

By | September 10, 2010

The motivation of aspect-oriented programming is to separate program logic.

Application can be devided in two concerns.

1. Core: Contains the program/business logic like calculation etc.
2. System: Contains system specific processes like logging.

In this example, I show you how to implement a AOP based logger. Logging is something you need very often. But you need to call the logger everywhere you want to write some logging data.

Instead of writing the logs into a file or eventlog I use the console in this example.

public interface IPerson
{
    void SayHello();
    string GetAddress();
    int DoSomething(int num, int num2);
}

public class Person : IPerson
{
    public void SayHello()
    {
        Logger.WriteBegin("SayHello"); // logging
            
        Console.WriteLine("Hello!");
            
        Logger.WriteEnd("SayHello"); // logging
    }

    public string GetAddress()
    {
        string retVal;
        Logger.WriteBegin("GetAddress"); // loggin
            
        retVal = "Route 66";

        Logger.WriteEnd("GetAddress"); // loggin... again
        return retVal;
    }

    public int DoSomething(int num, int num2)
    {
        int calc;
        Logger.WriteBegin("DoSomething"); // logging

        calc = num + num2;

        Logger.WriteEnd("DoSomething"); // logging
        return calc;
    }
}

Person obj = new Person();
obj.SayHello();
Console.WriteLine(obj.GetAddress());
Console.WriteLine(obj.DoSomething(33, 22).ToString());

As you see, every method of the Person class calls the logger twice (begin/end).
When you look at the code, you will see the core and the system specifc code.

Let’s analyze the SayHello() method.

public void SayHello()
{
    Logger.WriteBegin("SayHello"); // SYSTEM
    Console.WriteLine("Hello!");     // CORE - Logic
    Logger.WriteEnd("SayHello");  // SYSTEM
}

Console output without AOP

As I said at the beginning, AOP allows you to seperate this code. C#.NET doesn’t support AOP out of the box. But there are some nice tools (i.e. PostSharp) or frameworks like Spring.NET which can help you.

In this example I show you the implementation with Spring.NET.
First you have to know some few components of AOP:
– Joinpoint: Point of execution in a program like method invocation or exception throwing.
– Advice: Code execution at a specific joinpoint. There are four types of advices. (Before, After, Exception and Around) Around includes all of these.
– Proxy: Handles the advice invocation.

AOP Concept

Let’s implement a (around) logger advice. First we have to implement the IMethodInterceptor interface.
(Read the line comments!)

public class LoggerAdvice : IMethodInterceptor
{
    public object Invoke(IMethodInvocation invocation)
    {
        // Logging BEFORE method invocation
        Console.WriteLine();
        Console.WriteLine("--------------------");
        Console.WriteLine("Begin method call: " + invocation.Method.Name);
            
        // Log the passed arguments.
        if (invocation.Arguments != null)
            foreach (object arg in invocation.Arguments)
                Console.WriteLine(("Argument: " + arg.ToString()).PadLeft(15));


        Console.WriteLine(string.Empty);

        // Invoke the called method
        object methodReturn = invocation.Proceed();

        Console.WriteLine(string.Empty);

        // Logging AFTER method invocation
        Console.WriteLine("End method call: " + invocation.Method.Name);
        Console.WriteLine("--------------------");

        // Return the value of the method
        return methodReturn;
    }
}

As you see, we defined the logging in one class. Now let’s remove the “system” code from the previous example, so that only “core” logic is executed.

public interface IPerson
{
    void SayHello();
    string GetAddress();
    int DoSomething(int num, int num2);
}

public class Person : IPerson
{
    public void SayHello()
    {
        Console.WriteLine("Hello!");
    }

    public string GetAddress()
    {
        string retVal;
        retVal = "Route 66";
        return retVal;
    }

    public int DoSomething(int num, int num2)
    {
        int calc;
        calc = num + num2;
        return calc;
    }
}

Now you have to make a “connection” between the Person type and the LoggerAdvice. Otherwise, Spring.NET can’t run the code at the particular joinpoint.
I defined this config in my app.config file. It is a lot of configuration, but I think it is easy to understand.
(Analyze the “objects” element.) If you have question feel free to ask. ๐Ÿ˜‰
Ignore the “style” attributes. These attributes were hacked in by the WordPress SyntaxHighlighter. ๐Ÿ˜€

  
    
      
AdviceLog

PERFECT! Now the point is, when you create an instance of the Person object (with “new”) the logger won’t work. You have to load the object from the Spring.NET framework.

var appContext = ContextRegistry.GetContext();

// Get the person object. "PersonAd" is defined in App.config.
IPerson personObject = (IPerson)appContext["PersonAd"];

// Call the methods
personObject.SayHello();
Console.WriteLine(personObject.GetAddress());
Console.WriteLine(personObject.DoSomething(33, 22));

Now let look at the output!
Console output with AOP

Pretty cool! ๐Ÿ˜‰ Now you have sucessfully separated the “system” from the “core” code.
If you feel eager.. analyze the “Person” object in debug mode. As you see here the Spring.NET proxy class generates IL code at runtime.

Proxy object in Debug mode

Yes… I know AOP is cool. ๐Ÿ˜›