In my previous post I took you on a trip covering the evolution of the Dependency Injection pattern.
I asked for feedback on that post both on the ALT.net mailing list, a few internal message groups and on the microsoft architecture forums.
This post comes to you directly as a result of that feedback :)
Credits are to be given where they are due, the guy commenting me on the (somewhat obvious) exclusion of this in the previous post is Gael Fraiteur, the creator of the excellent PostSharp.
Aspect oriented programming
According to wikipedia, AOP is:
In software engineering, the programming paradigms of aspect-oriented programming (AOP), and aspect-oriented software development (AOSD) attempt to aid programmers in the separation of concerns, specifically cross-cutting concerns, as an advance in modularization. AOP does so using primarily language changes, while AOSD uses a combination of language, environment, and method.
[as a sidenote here, you should really check out the .net links at the bottom of the page, turns out there are quite a few AOP frameworks I have never even heard of!]
so, what is (slightly more comprehensible, at least if your the author of this blog) my definition of AOP?
AOP is nothing more than a way to inject behaviour into existing code.
Mostly this should be used for cross cutting concerns like logging, exception handling, security, performance monitoring and so on
Consider the following pieces of code:
public void MyMethod(){
this.Log.Log("started myMethod");
// do some stuff
this.Log.Log("finished myMethod");
}
I include exception handling here for the sake of completeness, personally I don't like to use AOP for exceptions
public void DoSomeTrickyStuff(){
Try{
//some tricky stuff that will fail;
} catch (Exception ex){
Log.Log(ex);
}}
and not to forget, my alltime favorite
public void SomeMethod(){
using(Trace("currentmethod", someparameters)){
//your method implementation goes here
}
}
Basically, Aspect Oriented Programming allows you to focus on the real method implementation and get's the pesky repeated code out of your way.
Depending on the used framework, AOP is implemented slightly different, giving access to different AOP features.
I'm going to start off with the simplest thing I can think off, taking baby steps once more:
Method Interception
Method interception is a bit of a strange concept at first, but compare it if you will to having a wire tap on a telephone line.
When you call your buddy the feds are listening in to that call, logging the time of the call, who called who and what was said..
How would you implement such a thing in .net?
You could do something like
event Action<IncomingCall> Called;
private voidi RaiseOnCalled(IncomingCall call){..}
public void AcceptCall(IncomingCall call){
RaiseOnCalled(call);
...
}
But this requires you to design your classes to be "interceptable", so it's basically unusable..
In my previous post on Dependency Injection, I took you on a history trip, going all the way back to the Factory pattern.
In this pattern you get an instance back of a class/interface, but you don't really know what instance that is..
So, what would happen if I gave you back a proxy?
A simple Proxy example would be
public interface ISomething{
void Foo();
}
becomes
public class SomethingProxy : ISomething {
private ISomething _worker;
public void Foo(){
// the method call is intercepted by the proxy
_worker.Foo();
}
}
Another example of a proxy is the generated class visual studio gives you when you add a web service/wcf service reference.
Now, off course this example doesn't really give you any extra features, as you still write it by hand/let vs generate it.
What you really need to pull AOP off is
- a way to write what needs to happen when a method is called just once
- a class that is reusable, no matter the interface(s) you need to implement
what you need is a:
Dynamic Proxy
A dynamic proxy class is a class that implements a list of interfaces specified at runtime such that a method invocation through one of the interfaces on an instance of the class will be encoded and dispatched to another object through a uniform interface. Thus, a dynamic proxy class can be used to create a type-safe proxy object for a list of interfaces without requiring pre-generation of the proxy class, such as with compile-time tools.
Now, the problem with .Net is that you're running into the limitations of the CLR on this one..
So, I'm not even going to try and give you a babystep-example here :p
Consider the Dynamic proxy from the Castle project
Here, you have the notion of
a proxy generator which returns you a proxy (duh)
an IInterceptor which, as it's name implies, intercepts method calls.
here's an example:
public interface ISomething {
void Foo();
}
public class Implementation : ISomething {
public void Foo() {
// no logging code here
}
}
the usage of the proxy becomes:
ISomething realImplementation = new Implementation();
ProxyGenerator generator = new ProxyGenerator();
ISomething proxy = generator.CreateInterfaceProxyWithTarget<ISomething>(realImplementation, new LoggingInterceptor());
proxy.Foo();
and this is the IInterceptor implementation:
public class LoggingInterceptor : IInterceptor {
public ILog Log { get; set; }
public void Intercept(IInvocation invocation) {
Log.Log(string.Format("start of method {0}", invocation.Method.Name));
invocation.Proceed();
Log.Log(string.Format("end of method {0}", invocation.Method.Name));
}
}
So, by using this dynamic proxy and interceptor you've just "injected" behaviour into your class, so welcome to AOP...
Creational patterns
I'm guessing you can easily imagine the possibilities with a service locator pattern..
One thing that you will find however, is that most AOP are marked by some creational pattern which returns a proxy of some sort.
Personally, I mostly classify these frameworks under runtime AOP, where the type you get aint what you were expecting
However, some other frameworks, like the already mentionned PostSharp do compile time code injection.
This means that when you compile your project code is added to the stuff you wrote yourself.
The added benefit here (to me at least) is that you're not limited to the creational patterns.
A loaded gun
In closing AOP is a way to limit the number of times you write the same "cross cutting concern" code.
However, if you start using AOP, consider that it really is a loaded gun, it's very easy to shoot yourself in the foot.
Maybe the most prominent gotcha is that what you see isn't what you get..
As a personal war story, an architect once told me that using AOP was not done, as no developer in his company really understood it, the code that logged an error was not in the same location as the code that caused the error and so on.
this leads me to the tip of the day, rethrowing exceptions without losing the call stack:
try {
//cause error
} catch (Exception ex) {
// do something with it
throw;
}
notice that it's throw; and not throw ex;
throw ex makes you lose the original callstack, throw preserves it.