About Me

I was born in Mobile, AL and graduated from Theodore High School in 1990. I received a BS in Pure Mathematics from the University of Alabama in 1995. I now reside in Hoover, AL.

Friday, October 26, 2007

Cecil, or How I Learned to Stop Logging and Love Mono

A friend of mine, Petar Vucetin, has often expressed interest in the ability to create a flight recorder for software that could record method entries, exits, and exceptions. We always knew it could be done with context-bound objects, as we could itercept calls to/from methods as they crossed the context boundary, but this solution was far from complete. Not only were you only able to intercept calls to/from context-bound objects, but the call actually had to cross a context boundary to be intercepted (i.e. calls from the context-bound object to itself were not intercepted). I played around with using Profiler to intercept calls at runtime, but I found the interfaces to be far too complex. I also looked into a couple of Aspect Oriented Programming (AOP) frameworks, but one relied on the objects to be context-bound and the other replaced the Microsoft compiler with their own. I had already discarded the context-bound solution and I was not about to rely on some third party compiler. In the end, I deemed the flight recorder project not worth the effort to attempt, and it remained Petar's White Whale.

And then came Mono. I was never too interested in the Mono project, as I never envisioned writing .NET programs for any platform other than Windows, but anything to shut those damn "write-once run-anywhere" java geeks up was good for the .NET community. While looking over AOP frameworks a couple of weeks ago, I ran across a link to the Mono.Cecil project. After reading about Mono.Cecil, I discovered that this was exactly that for which I had been searching. This framework allows you to inject CIL (the new MSIL) directly into compiled assemblies. I wrote a framework using Mono.Cecil called Dynamic Aspect Linking Engine (dale for short) that injects the code like the following examples:

Assume we have the following code:

 public static void PublicMethodTest (string testParam1, int testParam2)
 {
    // do something interesting here
 }

After running the injecter, the code becomes:

 public static void PublicMethodTest (string testParam1, int testParam2)
 {
    System.Reflection.MethodBase _dale_method = (new System.Diagnostics.StackFrame(0)).GetMethod();
    dalelib.AspectManager.EnterMethod(method, new object[] { testParam1, testParam2 });
 
    try
    {
       // do something interesting here
    }
    catch (Exception exception)
    {
       dalelib.AspectManager.MethodError(_dale_method, exception);
       throw;
    }
    finally
    {
       dalelib.AspectManager.ExitMethod(_dale_method);
    }
 }




The AspectManager class creates any defined aspects (defined by attributes) and notifies them of the entering, exiting, and/or exception.

The only caveat with injecting code with Cecil is that you must know CIL. The MSDN documentation on CIL is fairly extensive, but if you are more comfortable dragging and dropping components than you are writing them from scratch, then you may want to wait for a commercial product that does the work for you. I am seriously considering packaging the Dynamic Aspect Linking Engine up and either selling it or posting the source code on the internet, so check back if you are interested.

No comments: