Introduction
KingAOP - It's an AOP framework
which is essentially a free alternative of PostSharp. If you are familiar with PostSharp, then you can notice that KingAOP
has the similar interfaces. The main reason of creation of KingAOP was that currently we have several frameworks which provide a nice opportunities for AOP but no one has so simple
and explicit interaction with developer as PostSharp. I like API of PostSharp because it's predictable and anyone can understand it from first glance. The second reason was,
there are many questions on
stackoverflow
about free alternatives of PostSharp. It was pretty valuable argument to start development. The third reason was requirement to obtain the easy and transparent access to weaving code.
Also I wanted to get rid of dependency in generating code in post compile phase via some third party IL generator. Instead of it I use the native C# compiler without
shifting duties on some non official IL generator. On that moment I was really digging into "dynamic" C# and hence I realized that it's possible to get all AOP things which will based on "dynamic" + "DLR Trees"(for
metaprogramming).
Background
This article assumes that you're familiar with the concept of
AOP and
PostSharp framework.
Using the code
In this article I going to show you the basic and simple concept of interception methods. Let's start our diving in AOP world via well known
MethodInterceptionAspect<code><code>
aspect. This aspect allows you to intercept invocation of method call and do anything what you want. For example you can put the additional validation, caching, logging, wait/retry, automatic thread delegation, lazy loading, invoke additional methods or just not invoke original method and so on. Actually this aspect replaces the method body with a call to the aspect, then moves the original body elsewhere.
Our test example will be: to invoke method and print passed arguments with
values. I can agree it's not so useful requirement but it show you
the basic concept. In next parts we will look on more useful examples.
So to try KingAOP power let's create simple PrintArgsAspect
class inherited from MethodInterceptionAspect
with overridden OnInvoke
method.
Basically it will be our test aspect for experiments. PrintArgsAspect
will be responsible to print arguments values.
class PrintArgsAspect : MethodInterceptionAspect
{
public override void OnInvoke(MethodInterceptionArgs args)
{ }
}
The
OnInvoke
method will be invoked instead of real method and here is the place to do useful things. As you can see we acquire all arguments
via
MethodInterceptionArgs,
this entry point allow us to make decision what we will do next: change arguments, throw exception, invoke original method, skip invocation of original method and so on. As long
as we wanted just to take argument's value and print it, let's do that.
class PrintArgsAspect : MethodInterceptionAspect
{
public override void OnInvoke(MethodInterceptionArgs args)
{
string logData = PrintArgs("OnInvoke", args);
Console.WriteLine(logData);
args.Proceed();
}
string PrintArgs(string methodStage, MethodInterceptionArgs args)
{
var str = new StringBuilder();
str.AppendLine();
str.AppendLine(string.Format(methodStage + " {0} ", args.Method));
foreach (var argument in args.Arguments)
{
var argType = argument.GetType();
str.Append(argType.Name + ": ");
if (argType == typeof(string) || argType.IsPrimitive)
{
str.Append(argument);
}
else
{
foreach (var property in argType.GetProperties())
{
str.AppendFormat("{0} = {1}; ",
property.Name, property.GetValue(argument, null));
}
}
}
return str.ToString();
}
}
Also please notice that to invoke original method we call
Proceed method. Let's assume that we have TestRepository
class with Save
method where we want to apply our aspect.
class TestRepository
{
public void Save(TestEntity entity)
{ }
}
Also we have TestEntity
class which is our argument of Save
method of TestRepository
class.
class TestEntity
{
public int Number { get; set; }
public string Name { get; set; }
}
In order to apply some aspect of KingAOP we should inherit TestRepository
from IDynamicMetaObjectProvider
interface.
It's necessary for DLR to invoke our aspect via dynamic. You can think about it as indicator for DLR to do dynamic magic. The IDynamicMetaObjectProvider
require
to implement GetMediaObject
method. This method should always returns KingAOP's AspectWeaver
object which will generate code of aspect.
class TestRepository : IDynamicMetaObjectProvider
{
[PrintArgsAspect]
public void Save(TestEntity entity)
{ }
public DynamicMetaObject GetMetaObject(Expression parameter)
{
return new AspectWeaver(parameter, this);
}
}
The above implementation has method Save
with applied PrintArgsAspect
aspect and now if you invoke Save
method like
this testRepository.Save(entity);
the PrintArgsAspect
will intercept Save
(original) method invocation and print arguments.
It's time to show the demo, let's look on it.
class Program
{
static void Main(string[] args)
{
var entity = new TestEntity { Name = "Jon", Number = 99 };
dynamic repository = new TestRepository();
repository.Save(entity);
}
}
On console output we will have:
As you have noticed we printed argument values which passed to method Save
and we used dynamic
keyword. Without dynamic
it doesn't work.
Basically dynamic just tells C# compiler to generate necessary code for DLR to invoke our aspect.
Points of Interest
If you are curious about speed I would say that dynamic code blazingly fast.
It's not a joke! After first invocation of method the DLR compiles all code to native IL and gets very optimized delegate which will be invoked in further calls.
In other words you should think about dynamic as a normal C# code.
License
The entire KingAOP framework is licensed under the terms of the MIT license, meaning that you are free to use the library DLL in your commercial applications.