I've been hearing for a while now the talk in the .Net community about AOP. For those of you curious, AOP stands for Aspect Oriented Programming. The general concept is that in OO design you usually have classes/functions that span everything called cross-cutting concerns (caching, logging, security, etc.). AOP's goal is to separate those items from the main code, creating little modular bits of code to accomplish a task. At some point in time (run time or compile time), it weaves those bits of code back into the main code. Thus you never have to worry about adding in the logging, caching, etc. directly to the function/class as the AOP library does it for you which makes things easier to read and maintain.
Anyway, I used AOP back when I was a Java developer (AspectJ), however I never really bothered to look at the code under the hood. I built my aspects and went about my business. As of late I've been much more interested in "reinventing the wheel", which explains the ORM. So I felt why not create a small little library to do AOP? And as always, I decided to post about it here. I realize that over the past couple of months I've come out with 5 different libraries, Gestalt.Net, Blammo.Net, Echo.Net, DotCache, and DotExtension. Now Echo.Net was actually for a work related purpose that I developed on my own time because I thought it might be useful in other projects, but the other four were to help me with this series of posts. So I'm not just coming out with code for the sake of code, I have a plan... OK, not a plan but a general idea... OK, not a general idea, maybe a vague idea that may shape up at some point in time if I squint really hard.
Before I demotavate myself any more, let's move on to the various approaches to AOP. As far as I'm aware I've only seen about 6 approaches implemented, however Ayende Rahien mentions 7 approaches here. I have yet to see Runtime IL-weaving in action but then again I've never used Post Sharp. The other approaches are:
- Remoting Proxies
- Deriving from ContextBoundObject
- Compile-time subclassing
- Runtime subclassing
- Hooking into the profiler API
- Compile time IL-weaving
So let's go over each one and see why I didn't pick it. The first is Remoting Proxies are built into .Net and if you're interested in them, just look into the System.Runtime.Remoting.Proxies namespace. They're not exactly the most useful as they can only deal with interfaces and MarshalByRefObjects. That kills it right there as it limits its usefulness. The second approach is using ContextBoundObject. This approach is actually really simple. Any class that you wish to intercept calls to, just have it inherit from ContextBoundObject. So you can do things like this:
1: public class Temp2:ContextBoundObject
4: public string TempFunc()
6: return "A";
Note not exactly like that, but basically you do that and any calls to TempFunc get intercepted, allowing the MyAttribute to do work for you. Of course then you have to implement MyAttribute, set up an IMessageSink, IContextProperty, etc. which isn't too difficult. There are a couple major downsides to this approach though:
- You have to inherit from ContextBoundObject and C# doesn't allow for multiple inheritance
- It's slow. I mean REALLY slow.
- Say goodbye to generics (throws an error).
- It doesn't catch calls using this (or at least I couldn't get it to recognize the calls).
To me that's not worth it. The next is compile time subclassing. Basically that means we're doing code gen that creates a class that inherits from our initial class that we then use. It's not a bad approach actually. The main downside is that it only works with interfaces and virtual methods. The next approach is Runtime subclassing. With that approach it's IL gen instead of straight code gen which is then compiled. Once again, not that bad of an approach, same limitations as compile time, but it's usually a bit more flexible.
The next approach is hooking into the profiler API. To be honest, this approach is little more than compile time IL-weaving. Basically you're just inserting the code at compile time using the profiler API. As such it and Compile time IL-weaving have the same issues. Namely it's complex. The next approach is Runtime IL-weaving. Basically this is taking the byte code of the DLL/EXE and rewriting them so that your bits of code are added in. However unlike the profiler API/compile time approaches which simply rewrite the code on the disk, you're doing it at run time. That's it really, but personally I have no idea how you go about doing that in any sort of decent/non hack fashion.
So looking at each of these approaches, the one that seems the easiest to implement and still give me enough power to do what I want is the runtime subclassing. I mean I could do compile-time subclassing but since I've done some IL gen in the past for HaterAide ORM, it just seems easier to me. So if you're more interested in one of the other approaches, there are tons of other resources out there on them (well for some of them there are a lot of resources, not so much on others). That being said, in later posts I will be showing you my implementation using runtime subclassing. That's it for this post, so leave feedback and happing coding.