Friday, April 30, 2010

Today we are going to see some examples of Aspect Oriented Programming(AOP) and see how that can help us perform tasks that we otherwise might be forced to hard wire into our source code.

AOP can be thought of as a way of bringing new aspects/behaviors/features into our application without changing the original implementation.

The title for this article may be a little over the top, but if you're new to AOP, it may bring some new aspects to your life as a developer :)

We are going take a look at some examples and finish up by creating a simple data access library.

But first things first

Inversion Of Control

Before we delve into the world of AOP I thought it might be a good idea to talk a little about Inversion Of Control (IOC).

Inversion Of Control (also referred to as Dependency Injection) as a way of separating the creation of objects from their actual use.

I think maybe the term "Inversion of Control" is enough to scare people away from this type of software development. If you are already in control, why would you invert it as the term implies?. What does that even mean?

Lets illustrate this with an example. Imagine that we have some calculator class that can add two numbers and return the result.

publicclassCalculator

{

publicintAdd(intvalue1,intvalue2)

{

returnvalue1 + value2;

}

}

Using this class from the client code would look something like the following:

Calculatorcalculator =newCalculator();

varresult = calculator.Add(2, 2);

While the code certainly works, it creates a direct dependency between the client code and the concrete Calculator class. Let's try to make things a little better by creating an interface for the Calculator class to implement.

publicinterfaceICalculator

{

intAdd(intvalue1,intvalue2);

}

publicclassCalculator:ICalculator

{

publicintAdd(intvalue1,intvalue2)

{

returnvalue1 + value2;

}

}

Now the client code would change to something like:

ICalculatorcalculator =newCalculator();

varresult = calculator.Add(2, 2);

Now this is getting better by the minute, but we are still faced with the problem of how to create a Calculator instance without the dependency problem. I can almost hear some of you wondering "Why don't he just use the Abstract Factory Pattern?" And for those of you going "Abstract what?", lets go ahead and implement it for our naive little example.

As for the abstract product and concrete product, we already have those defined (ICalculator and Calculator). The client code would now be changed to this:

ICalculatorFactoryfactory =newCalculatorFactory();

ICalculatorcalculator = factory.CreateCalculator();

varresult = calculator.Add(2, 2);

Given that the CalculatorFactory class and the Calculator class is not contained in the same assembly, the client code does not longer need to know anything about the concrete Calculator class.

While this is a very naive example and does not fully show the power of the Abstract Factory Pattern, we still see that we need to do quite some work to create the abstractions we want.

In the world of IOC, we don’t really deal with abstract factories and all the plumbing needed. We just rely on the service container to resolve our dependencies.

Using a service container we could instead just write:

serviceContainer.GetService<ICalculator>();

We have no factory classes to support this so how can the service container figure out the concrete type?

Introducing LinFu.Ioc

Several years ago I came across this article written by my good friend and colleague, Philip Laureano. It was this very article that really got me started on creating loosely coupled applications in the first place.

There are a vast of Ioc frameworks available including the relatively new Unity framework from Microsoft, but I have yet to see something that is so simple to use and understand. As you will learn throughout this articles, I am not a big fan of XML configuration (or any configuration for that matter) and as you will see, configuring the LinFu service container takes only one single line of code.

Now lets see what we need to do in order to have the container return an ICalculator instance.

[Implements(typeof(ICalculator))]

publicclassCalculator:ICalculator

{

publicintAdd(intvalue1,intvalue2)

{

returnvalue1 + value2;

}

}

Notice the difference from our previous example? The ImplementsAttribute tells the container that this is the concrete implementation to create when a request for an ICalculator instance is made. I can only speak for my self here, but I find this a lot easier than learning how to configure this using some kind of XML format. Besides from being incredible easy to use, it is also very very flexible. If your not already familiar with LinFu.Ioc, I strongly recommend reading more about it here.

A word about project structure

When starting out to create a new library I always create at least three sub projects for the library. If we take the sample code for this article, this is how the solution is set up.

AopDemo

Contains the interfaces

AopDemo.Implementation

Contains the implementation of the interfaces

AopDemo.Tests

Contains the unit tests

The thing to notice here is that the client code, here represented by the unit tests, will never reference the assembly containing the implementation.

In fact, the implementation will never be referenced by any other assembly.

Aspect Oriented Programming

AOP can be thought of as a way of bringing new aspects/behaviors/features into our application without changing the original implementation.

Given the previous example, say that we wanted to do a Console.WriteLine every time we add two numbers. How could we do that without touching the actual Calculator class?

There are actually two ways of doing that and that is the "easy way" using a proxy and the rather more complicated approach that involves IL injection.

Both methods have their advantages and disadvantages, but the proxy approach most certainly have the advantage of being simple to implement.

So what we are going to to here is implement a proxy that adds our new aspect (Console.WriteLine) to the ICalculator implementation.

The Proxy

Now lets start off by looking at what a proxy actually is. A proxy is something that sits between the caller and the actual implementation.

As we can see the proxy also implements the ICalculator interface and hence the caller is still obliviously happy since it does not really care about the actual implementation as long as it implements the expected interface. In addition to forwarding method call from the caller to the actual implementation (Calculator), the proxy object also offers interception of the calls being made.

So what we need here is an interceptor that we can use to implement our simple logging mechanism.

Introducing LinFu.Proxy

The LinFu framework not only ships with an excellent IOC container, but it also contains a very flexible proxy library.

One thing that I really like about this library, is that it is built using the IOC principle/pattern which makes it easy if we need to handle corner case scenarios.

That is, however not within the scope of this article so we are going to get back to creating the interceptor we need to perform logging in the calculator.

publicclassCalculatorInterceptor:IInterceptor

{

publicobjectIntercept(IInvocationInfoinfo)

{

Console.WriteLine("The Add method has been invoked");

returninfo.TargetMethod.Invoke(info.Target, info.Arguments);

}

}

The Intercept method is called whenever the client code calls a method through the proxy object.

The question now remains...How do we tell the service container to return a Calculator Proxy instead of the actual Calculator?

Again the flexibility in LinFu opens up for several ways of doing that and here is an very elegant approach I am almost certain you have never seen before.

Let's change the CalculatorInterceptor into the following:

[Intercepts(typeof(ICalculator))]

publicclassCalculatorInterceptor:IInterceptor

{

publicobjectIntercept(IInvocationInfoinfo)

{

Console.WriteLine("The Add method has been invoked");

returninfo.TargetMethod.Invoke(info.Target, info.Arguments);

}

}

Notice the difference? Take a look at the Intercepts attribute. This attribute actually tells the service container to create a proxy object and forward method calls to this class.

Believe it or not, we have actually added a new aspect to the calculator with just 9 lines of code (Counting the curly brackets).

How's that for easy of use and flexibility?

The only requirement for the CalculatorInterceptor is that it is located on disc when the container is configured.

This means that we can add tracing to an already deployed application just by doing a simple XCopy.

This is getting so good that I think we should spend a little time to take this to the next level.

Say now that we wanted to allow for multiple logging targets and not just a simple Console.WriteLine.

We could of course add each logging target to the CalculatorInterceptor, but lets make this a little more exciting.

We start of by abstracting the actual logging out of the CalculatorInterceptor by creating an ILogger interface.

publicinterfaceILogger

{

voidLog(stringmessage);

}

Then we are going to ever so slightly alter the CalculatorInterceptor class.

[Intercepts(typeof(ICalculator))]

publicclassCalculatorInterceptor:IInterceptor,IInitialize

{

privateIEnumerable<ILogger> _loggers;

publicobjectIntercept(IInvocationInfoinfo)

{

foreach(varloggerin_loggers)

{

logger.Log("The Add method has been invoked");

}

returninfo.TargetMethod.Invoke(info.Target, info.Arguments);

}

publicvoidInitialize(IServiceContainersource)

{

_loggers = source.GetServices<ILogger>();

}

}

What’s new here is that we have implemented the IInitialize interface that is used by the service container to expose itself to the services instances it creates.

We then use the container to retrieve all implementations of the ILogger interface and handles the logging of to each instance.

And as for the Console.WriteLine, it has been moved to an ILogger implementation.

[Implements(typeof(ILogger))]

publicclassConsoleLogger:ILogger

{

publicvoidLog(stringmessage)

{

Console.WriteLine(message);

}

}

The beauty of this is that we can now create as many ILogger implementations as we want and they will all be invoked when the Add method is invoked.

Pretty cool, wouldn't you say?

From naiveness towards the real world

While this so far has shown how flexible the LinFu framerwork is, it still remains a fact that the calculator example is pretty naive.

Let's pick it up a notch and create something useful. Why don't we create a DBMS independent data access library with profiling capabilities? That might sound like a daunting task, but thanks to LinFu, this practically becomes a breeze.

Let's boil this data access paradigm down to what is it that we really need? We need some object that we can use to execute sql, right?

For me it sounds like a IDbCommand implementation should fit the picture just perfectly. How do we get a IDbCommand implementation? Simple, we just hand it off to the container like this:

vardbCommand = ServiceContainer.GetService<IDbCommand>();

But wait a minute, how does the container know what implementation of IDbCommand to create?

The answer is that is does not so we need to teach the container how to create an IDbCommand instance.