Friday, April 30, 2010

Bringing new aspects to life using the LinFu framework


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.


public
 class Calculator

{

    public int Add(int value1, int value2)

    {

        return value1 + value2;

    }

}

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

Calculator calculator = new Calculator();

var result = 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.

public interface ICalculator

{

    int Add(int value1, int value2);

}

 

public class Calculator : ICalculator

{

    public int Add(int value1, int value2)

    {

        return value1 + value2;

    }

}


Now the client code would change to something like:

ICalculator calculator = new Calculator();

var result = 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.

First we need an abstract factory

public interface ICalculatorFactory

{

    ICalculator CreateCalculator();

}


Then we need a concrete factory

public
 class CalculatorFactory : ICalculatorFactory
{
    public ICalculator CreateCalculator()
    {
        return new Calculator();
    }
}

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:

ICalculatorFactory factory = new CalculatorFactory();

ICalculator calculator =  factory.CreateCalculator();                      

var result = 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.

serviceContainer.LoadFrom(AppDomain.CurrentDomain.BaseDirectory, "*.dll");

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

[Implements(typeof(ICalculator))]

public class Calculator : ICalculator

{

    public int Add(int value1, int value2)

    {

        return value1 + 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.

public class CalculatorInterceptor : IInterceptor

{              

    public object Intercept(IInvocationInfo info)

    {

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

        return info.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))]

public class CalculatorInterceptor : IInterceptor

{              

    public object Intercept(IInvocationInfo info)

    {

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

        return info.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.

public interface ILogger

{

    void Log(string message);

}


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

[Intercepts(typeof(ICalculator))]

public class CalculatorInterceptor : IInterceptor, IInitialize

{

    private IEnumerable<ILogger> _loggers;

 

    public object Intercept(IInvocationInfo info)

    {

        foreach (var logger in _loggers)

        {

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

        }

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

    }

 

    public void Initialize(IServiceContainer source)

    {

        _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))]

public class ConsoleLogger : ILogger

{

    public void Log(string message)

    {

        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:

var dbCommand = 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.

The code below shows a rudimentary factory implementation.

[Factory(typeof(IDbCommand))]

public class DbCommandFactory : IFactory<IDbCommand>

{       

    public IDbCommand CreateInstance(IFactoryRequest request)

    {

        var connectionStringSettings = GetConnectionStringSetting(request.ServiceName);

        var providerFactory = CreateProviderFactory(connectionStringSettings);

        var connection = providerFactory.CreateConnection();

        connection.ConnectionString = connectionStringSettings.ConnectionString;

        connection.Open();

        return connection.CreateCommand();           

    }

 

    private static DbProviderFactory CreateProviderFactory(

        ConnectionStringSettings connectionStringSettings)

    {

        return DbProviderFactories

            .GetFactory(connectionStringSettings.ProviderName);

    }  

 

    private static ConnectionStringSettings GetConnectionStringSetting(string connectionName)

    {

        if (String.IsNullOrEmpty(connectionName))

            return ConfigurationManager.ConnectionStrings

                .Cast<ConnectionStringSettings>().Last();

        return

            ConfigurationManager.ConnectionStrings

            .Cast<ConnectionStringSettings>().Where(

                c => c.Name.EndsWith(connectionName)).FirstOrDefault();

    }

}

Luckily for us, most of the abstractions has already been done for us. We just need to hook up with the appropriate DbProviderFactory and we are pretty much good to go.

We can now go ahead and configure our connection in app/web config and that's all we really need to do. We can now get a ready and willing IDbCommand instance by doing:

var dbCommand = ServiceContainer.GetService<IDbCommand>();

Sweet, but didn't I promise profiling capabilities? Okay, let's spend another five minutes.

We start off by creating an interface for the profilers

public interface IDbProfiler

{

    void BeforeExecute(IDbCommand dbCommand, MethodInfo methodInfo, object[] arguments);

    void AfterExecute(IDbCommand dbCommand, MethodInfo methodInfo, object[] arguments);

}

Next we need an interceptor that intercepts calls made to the actual DbCommand.

[Intercepts(typeof(IDbCommand))]

public class DbCommandInterceptor : IInterceptor, IInitialize

{

    private IEnumerable<IDbProfiler> _profilers;

 

    public object Intercept(IInvocationInfo info)

    {

        foreach (var dbProfiler in _profilers)

            dbProfiler.BeforeExecute((IDbCommand) info.Target,

                info.TargetMethod, info.Arguments);

 

        var returnValue =  info.TargetMethod.Invoke(info.Target, info.Arguments);

 

        foreach (var dbProfiler in _profilers)

            dbProfiler.AfterExecute((IDbCommand) info.Target,

                info.TargetMethod, info.Arguments);

 

        return returnValue;

    }

 

    public void Initialize(IServiceContainer source)

    {

        _profilers = source.GetServices<IDbProfiler>().ToList();

    }

}

As we can see we are doing much of the same that with did with in the calculator  example.

Now lets finish this off by creating a sample IDbCommand profiler.

[Implements(typeof(IDbProfiler))]

public class ConsoleDbProfiler : IDbProfiler

{

    private readonly Stopwatch _stopwatch = new Stopwatch();

 

    public void BeforeExecute(IDbCommand dbCommand, MethodInfo methodInfo, object[] arguments)

    {           

        if (ShouldProfile(methodInfo))

        {

            _stopwatch.Reset();

            _stopwatch.Start();

        }

    }

 

    public void AfterExecute(IDbCommand dbCommand, MethodInfo methodInfo, object[] arguments)

    {

        if (ShouldProfile(methodInfo))

        {           

            _stopwatch.Stop();               

            Console.WriteLine(string.Format("The command '{0}' executed in {1} milliseconds"

                , dbCommand.CommandText, _stopwatch.ElapsedMilliseconds));

 

        }

    }

 

    private static bool ShouldProfile(MethodInfo methodInfo)

    {

        var methodName = methodInfo.Name;

        return (methodName == "ExecuteReader"

                || methodName == "ExecuteNonQuery"

                || methodName == "ExecuteScalar");

 

    }

}

The fact is that we use a similar approach at work at it has proven invaluable to us when it comes to hunting down long running queries.

The following code shows the execution of the query:

var dbCommand = ServiceContainer.GetService<IDbCommand>();

dbCommand.CommandText = "SELECT * FROM Orders";

var reader = dbCommand.ExecuteReader(CommandBehavior.CloseConnection);

And in our debug output window we can now observe the following:

The command 'SELECT * FROM Orders' executed in 116 milliseconds

And that my friends, is how we add new aspects to even a sealed type. (Yes, the SqlDbCommand is actually sealed)

Please note that all exception handling has been omitted for the sake of brevity.

Conclusion

As we have seen, using the LinFu framework, taking the shift towards AOP is ridiculously simple to overcome.

We have seen how we can add new aspects to existing classes with out touching the original code and even implemented a simple data access library.

We can also draw the conclusion that AOP helps serving the Separation of Concerns principle as we don’t clutter our classes with aspects that is beyond their initial intent.

So the next time you create a new class, make sure you do so by implementing an interface.

You never know when new requirements (aspects) arrive.

Enjoy!!!!

2 comments:

A.Granheim said...

Interesting :)
Good explanation!
Added to my todo list

Anonymous said...

Cool, thanks alot.