<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!--------------------------------------------------------------------------->
<!-- INTRODUCTION
The Code Project article submission template (HTML version)
Using this template will help us post your article sooner. To use, just
follow the 3 easy steps below:
1. Fill in the article description details
2. Add links to your images and downloads
3. Include the main article text
That's all there is to it! All formatting will be done by our submission
scripts and style sheets.
-->
<!--------------------------------------------------------------------------->
<!-- IGNORE THIS SECTION -->
<html>
<head>
<title>The Code Project</title>
<style>
BODY, P, TD
{
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 10pt;
}
H2, H3, H4, H5
{
color: #ff9900;
font-weight: bold;
}
H2
{
font-size: 13pt;
}
H3
{
font-size: 12pt;
}
H4
{
font-size: 10pt;
color: black;
}
PRE
{
background-color: #FBEDBB;
font-family: "Courier New" , Courier, mono;
white-space: pre;
}
CODE
{
color: #990000;
font-family: "Courier New" , Courier, mono;
}
</style>
<link rel="stylesheet" type="text/css" href="http://www.codeproject.com/App_Themes/Std/CodeProject.css">
</head>
<body bgcolor="#FFFFFF" color="#000000">
<!-- Fill in the details (CodeProject will reformat this section for you) -->
<pre>
Author: Guirec Le Bars
Email: glebars20@hotmail.com
</pre>
<h1>
Aspect Oriented Programming: learn step by step and roll your own implementation!</h1>
<p>
A journey into AOP land with concerns, pointcuts, joinpoints, advices, aspects,
interceptors, proxies, targets, mix-ins, composites...</p>
<h2>
Introduction</h2>
<p>
AOP stands for Aspect Oriented Programming. I guess every reader is familiar with
the OP part of the acronym so we will have to clarify what Aspect means and don’t
worry we’ll come to that later in the article.</p>
<p>
I’ll (try to) keep this article at beginner level. Knowledge of Object Oriented
Programming concepts is the only requirement to read further!</p>
<p>
In my opinion understanding properly a concept make you a better consumer of its
implementation. But, I do understand that the article is a bit long so if you feel
bored or discouraged I still encourage you to jump to the implementation part. You'll
still be able to come back to theory later.
</p>
<h2>
Advanced developers, read this!</h2>
<p>
If you are familiar with AOP then don't leave yet!<br />
Let me already disclose straight away what this article has to offer...
</p>
<p>
I will introduce an <strong>interception technique </strong>which can (and do actually
:-) ):
</p>
<ul>
<li>Intercept <b>any class</b> (including sealed, static, value types)</li>
<li>Intercept <b>constructors</b></li>
<li>Intercept <strong>type initializers</strong></li>
<li>Intercept instance <strong>methods, properties and eventsand events</strong> (even
if they are not marked as virtual)</li>
<li>Intercept <b>static</b> methods, properties and events</li>
</ul>
<p>
Without</p>
<ul>
<li>Weaving your code or your assemblies</li>
<li>emitting IL code</li>
<li>using any dynamic stuff</li>
<li>modifying your target class</li>
<li>forcing the weavers to implement anything (such as MarshalByRef)</li>
</ul>
<p>
Basically we are talking about a pure managed code technique which could run on
.Net 1.1 (actually I use bits of Linq but you can change t that easily) and which
allows you to intercept almost anything you might think of.
</p>
<p>
Let's be more clear. With the following technique:</p>
<p>
you can intercept stuff such as <code>System.DateTime.Now</code> or <code>System.IO.File</code>
operations!
<br />
you don't have the usual limitations of the most popular interceptions library.</p>
<p>
Are you guys doubting ? then read further!!
</p>
<h2>
Background</h2>
<p>
Some might think they have not made their full journey into Object Oriented Programming
so why would they switch from OOP to AOP and abandoned all the concepts they hardly
have learnt over the years? Answer is simple: there is no switch. <b>There is no: OOP
vs AOP!</b> AOP is one of these concepts which name, in my opinion, is misleading.
Embracing the AOP principles lets you dealing with classes, objects, interfaces,
inheritance, polymorphism, abstraction etc… so there is no way you get lost as you
are still fully immersed in the OOP world.</p>
<p>
When applying AOP concepts in your code you are attempting to relax one particular,
and not the least, principle of OOP which is encapsulation to adress cross-cutting
concerns (we'll come back to that later on).
</p>
<p>
Back in the old days, when internet was only yellow pages, bulleting boards and
usenet, you were better to read books if you wanted to learn anything (comment for
the y generation : a book is a thing with written sheets of paper stuffed in it).
And all these books would approximately remind you this regarding the OOP subject:</p>
<ul>
<li>Rule #1: you have to encapsulate all you data and code</li>
<li>Rule #2: never ever break Rule #1</li>
</ul>
<p>
<strong>Encapsulation</strong> has been the ultimate goal for introducing OOP concepts
in 3<sup>rd</sup> generation languages (<a href="http://en.wikipedia.org/wiki/Third-generation_programming_language">3GL</a>).
</p>
<cite><u>Wikipedia:</u><br />
<b>Encapsulation</b> is used to refer to one of two related but distinct notions,
and sometimes to their combination: </cite>
<ul>
<li><cite>A language mechanism for restricting access to some of the object’s components.</cite></li>
<li><cite>A language construct that facilitates the bundling of data with the methods
(or other functions) operating on that data.</cite></li>
</ul>
<p>
AOP, in a way, is claiming that it, <u>sometimes</u>, should be possible to use:
<br />
<b>a language construct that facilitates the bundling of methods (or other functions)
operating with encapsulated data without the data.</b>
</p>
<p>
Got that? Then you get all that is to know about the theory. Good job!</p>
<p>
Now we are naturally leaded to the 2 following questions:
</p>
<ul>
<li>When is “sometimes”?</li>
<li>Why should it be possible? </li>
</ul>
<h2>
On usefulness of AOP... some scenarii</h2>
<p>
Let's take a look at a the following situations:</p>
<h3>
Scenario A</h3>
<p>
You are software developer in a bank. The bank has a pretty working operational
system. The business is running smoothly. Government emits a policy which enforces
banks to commit on some sort of transparency. Whenever money goes in or out of the
bank it should be logged. The government publicly said that this is a first measure
towards transparency but that more is to be expected.
</p>
<h3>
Scenario B</h3>
<p>
Your web application has been released to test team. All functional tests passed
but the application failed at load testing. A non-functional requirement stated
that no page should take more than 500 ms to process on the server. After analysis
there are dozens of queries made to the database that could be avoided by caching
the results.</p>
<h3>
Scenario c</h3>
<p>
You have spent the last 2 years modeling your domain model in a perfect library
consisting of 200+ classes. Lately you’ve been told that a new application front-end
will be written and this guy needs to bind your objects to the UI. But to facilitate
that task all your classes should now implement <code>INotifyPropertyChanged</code>.</p>
<p>
These examples are valid in terms of the why and when AOP could come to the rescue.
These scenarii have the following in common:</p>
<h3>
Cross-cutting concerns</h3>
<p>
<u>When is "sometimes”?</u></p>
<p>
Some classes (Bank class, Data access services, Domain model classes, etc…) designed
to achieve a given functionality have to be modified to handle a requirement which
is basically “not their own business”.</p>
<ol>
<li>The Bank class purpose is money exchange. The logging concern is Government’s interest.</li>
<li>The Data Services classes purpose is to retrieve data. The data caching concern
is a non-functional requirement.</li>
<li>The domain model classes purpose is to handle your company’s business. The concern
about notification of property changed is in the UI interest.</li>
</ol>
<p>
It is whenever you have to write some code over different classes to fulfill an
interest external to these classes. In AOP dialect it is whenever you have a <strong>
cross-cutting concern</strong>.</p>
<p>
The notion of <strong>cross-cutting concern</strong> is centric to AOP. <b>No cross-cutting
concern = no need for AOP!</b></p>
<p>
<u>why should it be possible?</u></p>
<p>
Let’s take a closer look at Scenario C.<br />
Your problem is that you have an average of 5 properties exposed by each class in
your domain model. With 200+ classes you will have to implement (copy/paste) more
than 1,000 times some boiler plate code to transform something which looks like
this:</p>
<pre lang="C#">
public class Customer
{
public string Name { get; set; }
}
</pre>
<p>
Into something like that:</p>
<pre lang="C#">
public class Customer : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _Name;
public string Name
{
get { return _Name; }
set
{
if (value != _Name)
{
_Name = value;
SignalPropertyChanged("Name");
}
}
}
void SignalPropertyChanged(string propertyName)
{
var pcEvent = this.PropertyChanged;
if (pcEvent != null) pcEvent(this, new PropertyChangedEventArgs(propertyName));
}
}
</pre>
<p>
Uh! And that is for one property only! BTW, did you know the intern left 2 days
ago? :-)</p>
<p>
I think you get the why without further explanation...</p>
<p>
It should be possible <i>"to bundle the methods operating with encapsulated data without
the data"</i> in other words : externalise the implementation of the cross-cutting
<code>INotifyPropertyChanged</code> concern with no or minimum impact on domain
model classes like <code>Customer</code>.</p>
<p>
If we can achieve that then we will:</p>
<ol>
<li>Have a proper separation of concerns</li>
<li>Avoid code repetition and thus facilitate code maintenance </li>
<li>Avoid hiding domain classes core business under tons of boiler plate code</li>
</ol>
<p>
Yeahh... ok, that's all nice and fancy and stuff but <b>how can we do?</b></p>
<h3>
The theorical answer</h3>
<p>
We have a <b>cross-cutting concern</b> which requires some code to be executed in
several classes (<strong>targets</strong> from now on).<br />
The implementation (the code which implements Logging, or Cache, or whatever) is
simply called <b>concern</b> in the AOP world.
</p>
<p>
We should then be able to attach (inject, introduce, etc... choose your word) our
<b>concern</b> (I repeat because it is important: <u>the <b>concern</b> is the implementation</u>
for your <b>cross-cutting concern</b>) at any chosen place of the <strong>target</strong>.<br />
And we should be able to choose any of the following places of the <strong>target</strong>
to attach our <strong>concern</strong>:</p>
<ul>
<li>Static initializers</li>
<li>Constructors</li>
<li>Static Property getters and setters</li>
<li>Instance Property getters and setters</li>
<li>Static methods</li>
<li>Instance Methods</li>
<li>Destructors</li>
</ul>
<p>
In a perfect AOP world we should be able to attach our <strong>concern</strong>
at any line of code of the <strong>target</strong>.</p>
<p>
Fine, but if we want to attach a <b>concern</b> we need a hook in the <strong>target</strong>,
don’t we? Yes captain!<br />
In AOP the notion of that hook (the place where your <strong>concern</strong> is
going to be attached for execution) has a name: it is a <b>pointcut</b>. And the
place from where you actualy attach the code has also a name : it is a <b>joinpoint</b>.</p>
<p>
Clear enough? Maybe not.... Here is some pseudo-code that hopefully demonstate the
idea:</p>
<pre>
// Target class
class BankAccount
{
public string AccountNumber {get;}
public int Balance {get; set;}
void Withdraw(int AmountToWithdraw)
{
<b>:public pointcut1;</b> // a pointcut (imagine something like a label for goto statement in BASIC or T-SQL etc...)
Balance -= AmountToWithdraw;
}
}
// Concern
<b>concern</b> LoggingConcern
{
void LogWithdraw(int AmountToWithdraw)
{
// Here you have to imagine that some kind of 'magic' has happened
// and 'this' is an instance of the BankAccount class.
Console.WriteLine(<b>this.AccountNumber</b> + " withdrawal on-going...");
}
}
class Program
{
void Main()
{
// get a reference to the pointcut marker through reflection
pointcut = typeof(Bank).GetPointcut("<b>pointcut1</b>");
// this is the joinpoint
<b>LoggingConcern.Join(cutpoint, LogWithdraw); </b>
// After joinpoint the runtime should have (in a sort of registry)
// a record which tells to execute our LoggingConcern at pointcut1 of Bank class
}
}
</pre>
<p>
Would'nt it be great to have such mechanism available out of the C# box???
</p>
<h3>
A few more definitions</h3>
<p>
Before we move on to our actual implementation let's introduce a few more definitions...</p>
<p>
<u>What is an <b>Aspect</b>?</u><br />
It is the association of a <b>concern</b>, a <b>point cut</b> and a <b>joinpoint</b>.<br />
Think of it for a second and I hope it will be crystal clear: the fact that I have
a Logging mechanism (<b>concern</b>), that I register its log method to be executed
(<b>joinpoint</b>) at a given place of my application code (<b>pointcut</b>) is
one <b>aspect</b> of my application.
</p>
<p>
But wait a minute... What could/should a <b>concern</b> be allowed to do once injected?</p>
<p>
<b>Concerns</b> are categorized into 2 categories:</p>
<ul>
<li><u><b>Side effects</b>:</u><br />
A <b>side effect</b> is a <b>concern</b> which is not changing the behavior of the
code at <b>pointcut</b>. A <b>side effect</b> just introduce an additional action
to perform.<br />
A Logging <b>concern</b> is a good example of a <b>side effect</b>: whenever the
runtime execute the targeted method (eg:<code>Bank.Withdraw(int Amount)</code>)
the <code>LoggingConcern.LogWithdraw(int Amount)</code> method will be executed
and the <code>Bank.Withdraw(int Amount)</code> method will continue execution.<br />
<br />
</li>
<li><u><b>Advices</b>:</u><br />
An <b>advice</b> is a <b>concern</b> which might change the input/output of the
method.<br />
A Caching <b>concern</b> is a perfect example: Whenever the runtime execute the
targeted method (eg: <code>CustomerService.GetById(int Id)</code>) the <code>CachingConcern.TryGetCustomerById(int
Id)</code> will be executed and will force the <code>CustomerService.GetById(int Id)</code>
method to return with the value found in cache, if any, otherwise will let the execution
continue.<br />
<br />
<b>Advices</b> should be allowed to:<br />
<ul>
<li>Inspect the input parameters at targeted pointcut and modify them if needed</li>
<li>Cancel the execution of the targeted method and replace it with a different implementation</li>
<li>Inspect the output result od the targeted method and modify or replace it</li>
</ul>
</li>
</ul>
<p>
At that point if you are still reading then congratulations! Bravo! Parce que vous
le valez bien ;-)
</p>
<p>
We are done with the general concepts and ideas of AOP. Let's move forward and see
how we can get close to that with C#...</p>
<h2>
Show me some code ou je tue le chien!</h2>
<h3>
<b>Concerns</b></h3>
<p>
The <b>concern</b> should have a magic <code>this</code> behavior which is of our
<strong>target</strong> type.<br />
That's no problemo!
</p>
<pre lang="C#">
public interface IConcern<T>
{
T This { get; } // ok, that's a bit of cheating but who cares?
} </pre>
<h3>
<b>Reference to pointcuts</b></h3>
<p>
There is no easy way to get <b>pointcuts</b> for every single line of code. But
we can get one at each method call and that's fairly easy by using the <a href="http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.aspx">
<code>System.Reflection.MethodBase</code></a> class. MSDN is not really verbose
about it: <cite>Provides information about methods and constructors.</cite>[sic].
</p>
<p>
Between you and me using <code>MethodBase</code> for getting reference to <b>pointcuts</b>
is the most powerful possibility at your disposition.
</p>
<p>
You can get reference to pointcuts for Constructors, Methods, Properties and Events
as for .Net almost anything you declare in your code (apart from fields) ends up
being a method...<br />
See yourselves:
</p>
<pre lang="C#">
public class Customer
{
public event EventHandler<EventArgs> NameChanged;
public string Name { get; private set; }
public void ChangeName(string newName)
{
Name = newName;
NameChanged(this, EventArgs.Empty);
}
}
class Program
{
static void Main(string[] args)
{
var t = typeof(Customer);
// Constructor (not limited to parameterless)
var pointcut1 = t.GetConstructor(new Type[] { });
// The ChangeName method
var pointcut2 = t.GetMethod("ChangeName");
// the Name property
var nameProperty = t.GetProperty("Name");
var pointcut3 = nameProperty.GetGetMethod();
var pointcut4 = nameProperty.GetSetMethod();
// Everything about the NameChanged event
var NameChangedEvent = t.GetEvent("NameChanged");
var pointcut5 = NameChangedEvent.GetRaiseMethod();
var pointcut6 = NameChangedEvent.GetAddMethod();
var pointcut7 = NameChangedEvent.GetRemoveMethod();
}
}
</pre>
<h3>
<b>Joinpoints</b></h3>
<p>
Writing the code for joining is fairly easy as well. Look at the signature of the
method below :<br />
</p>
<code>void Join(System.Reflection.MethodBase pointcutMethod, System.Reflection.MethodBase
concernMethod);</code>
<p>
We can add that signature to a sort of registry that we will provide later on and
we can already imagine writing code like this one!!!</p>
<pre lang="C#">
public class Customer
{
public string Name { get; set;}
public void DoYourOwnBusiness()
{
System.Diagnostics.Trace.WriteLine(Name + " is doing is own business");
}
}
public class LoggingConcern : IConcern<Customer>
{
public Customer This { get; set; }
public void DoSomething()
{
System.Diagnostics.Trace.WriteLine(This.Name + " is going to do is own business");
This.DoYourOwnBusiness();
System.Diagnostics.Trace.WriteLine(This.Name + " has finished doing its own business");
}
}
class Program
{
static void Main(string[] args)h
{
// Get a pointcut for Customer.DoSomething();
var pointcut1 = typeof(Customer).GetMethod("DoSomething");
var concernMethod = typeof(LoggingConcern).GetMethod("DoSomething");
// Join them
AOP.Registry.Join(pointcut1, concernMethod);
}
}</pre>
<p>
How far are we from our pseudo-code? Personally I would say not much...<br />
What's next then?</p>
<h2>
Glueing everything together...</h2>
<p>
That's where problems and fun start at the same time!
</p>
<p>
But let's start simple with
</p>
<h3>
The registry</h3>
<p>
The registry will keep records about <b>joinpoints</b>. It's a singleton list of
joinpoint items.<br />
A <b>joinpoint</b> is a simple struct :
</p>
<pre lang="C#">
public struct Joinpoint
{
internal MethodBase PointcutMethod;
internal MethodBase ConcernMethod;
private Joinpoint(MethodBase pointcutMethod, MethodBase concernMethod)
{
PointcutMethod = pointcutMethod;
ConcernMethod = concernMethod;
}
// Utility method to create joinpoints
public static Joinpoint Create(MethodBase pointcutMethod, MethodBase concernMethod)
{
return new Joinpoint (pointcutMethod, concernMethod);
}
}
</pre>
<p>
Nothing fancy... It should as well implement <code>IEquatable<Joinpoint></code>
but for making the code shorter here I have intentionally removed it</p>
<p>
And the registry: The class is called <code>AOP</code> and implements the singleton
pattern. It exposes its unique instance through a public static property named <code>
Registry</code></p>
<pre lang="C#">
public class AOP : List<Joinpoint>
{
static readonly AOP _registry;
static AOP() { _registry = new AOP(); }
private AOP() { }
public static AOP Registry { get { return _registry; } }
[MethodImpl(MethodImplOptions.Synchronized)]
public void Join(MethodBase pointcutMethod, MethodBase concernMethod)
{
var joinPoint = Joinpoint.Create(pointcutMethod, concernMethod);
if (!this.Contains(joinPoint)) this.Add(joinPoint);
}
}
</pre>
<p>
With the <code>AOP </code>class we can now write construct like :
</p>
<pre lang="C#">AOP.Registry.Join(pointcut, concernMethod);</pre>
<h3>
Houston, we've got a problem</h3>
<p>
We've got an obvious and serious problem now to cope with. If a developer writes
code like...</p>
<pre lang="C#">
var customer = new Customer {Name="test"};
customer.DoYourOwnBusiness();
</pre>
<p>
... there is just no reason why our registry would be consulted, so there is no
way that our <code>LoggingConcern.DoSomething()</code> method is executed...</p>
<p>
Our problem is that .Net does not provide us with a simple way to intercept such
calls out of the box.</p>
<p>
As there is no native way then some <u>work around</u> must be implemented. The
capabilities of your work around is going to drive the capabilities of your AOP
implementation.<br />
The goal of this aricle is not to discuss all possible interception techniques but
take note that <b>the interception model is the key differentiator</b> between all
AOP implementations.<br />
The SharpCrafters website (owners of PostSharp) is providing some clear information
on the 2 major techniques:
</p>
<ul>
<li><a href="http://www.sharpcrafters.com/aop.net/compiletime-weaving">Compile-time
weaving</a></li>
<li><a href="http://www.sharpcrafters.com/aop.net/runtime-weaving">Run-time weaving</a></li>
</ul>
<h3>
Our interception technique: <a href="http://en.wikipedia.org/wiki/Proxy_pattern">Proxying</a></h3>
<p>
There is not much of a secret if you want to intercept all calls made to a class
you have 3 choices:</p>
<ol>
<li>Create your own language and compiler to produce .net assemblies: when compiling
you can inject whatever you want everywhere you want.</li>
<li>Implement a solution which modifies the runtime behavior of assemblies</li>
<li>Give a proxy to your consumer and intercept calls using an Interceptor class while
marshaling the real subject (<strong>target</strong>)</li>
</ol>
<p style="font-size: 10px; padding-left: 40px;">
<i>For advanced guys: I voluntarily don't mention Debugger API and Profiler API
possibilities which are not viable for production scenarii.<br />
For very advanced one: An hybrid of solutions 1 and 2 using the Roslyn API should
be feasible and, as far as I know, it is still to be invented. A bon entendeur...</i></p>
<p>
Apart if you need to provide <b>pointcuts</b> at any single line of code then it
seems that the 2 first solutions are a bit of over-engineering.<br />
We'll go for the 3rd solution. Take note that usage of proxying technique comes
with a good and a bad news:
</p>
<p>
<u>The bad news</u> is that your <b>target</b> object must be swapped at runtime
with a proxy object instance. Implying that if you want to intercept things such
as constructors you'll have to delegate construction of your <b>target</b> class
instances to a factory (that's a <b>cross-cutting concern</b> that this implementation
won't solve :-(). If you already have an instance of the <strong>target</strong>
class then you will have to explicitely <i>ask</i> for the swap to happen. For the
IOC and Dependency Injection ninjas the delegation of objects creation will be less
than an issue. For others it means they'll have to use a factory if they want to
use our interception technique at its full extent. But don't worry we are going
to implement that factory.</p>
<p>
<u>The good news</u> is that we have nothing to do to implement a proxy. The class
<code>System.Runtime.Remoting.Proxies.RealProxy</code> will build it for us in a
highly optimized way.</p>
<p>
In my opinion the class name does not reflect its use. This class is not a Proxy
it is an Interceptor. But anyway that class will provide us with a Proxy by calling
its method <code>GetTransparentProxy()</code> and that's the only thing we need.</p>
<p>
So the skeleton for our interceptor is :</p>
<pre lang="C#">
public class Interceptor : RealProxy, IRemotingTypeInfo
{
object theTarget { get; set; }
public Interceptor(object target) : base(typeof(MarshalByRefObject))
{
theTarget = target;
}
public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
{
IMethodCallMessage methodMessage = (IMethodCallMessage) msg;
MethodBase method = methodMessage.MethodBase;
object[] arguments = methodMessage.Args;
object returnValue = null;
// TODO:
// here goes the implementation details for method swapping in case the AOP.Registry
// has an existing joinpoint for the MethodBase which is hold in the "method" variable...
// if the Registry has no joinpoint then simply search for the corresponding method
// on the "theTarget" object and simply invoke it... ;-)
return new ReturnMessage(returnValue, methodMessage.Args, methodMessage.ArgCount, methodMessage.LogicalCallContext, methodMessage);
}
#region IRemotingTypeInfo
public string TypeName { get; set; }
public bool CanCastTo(Type fromType, object o) { return true; }
#endregion
}
</pre>
<p>
Some explanations are required here as we are now touching the heart of the implementation....
</p>
<p>
The <code>RealProxy</code> class exists to serve the purpose of intercepting calls
from remote objects and marshal a targeted object. By remote here you must understand
really remote like : objects living in another application, another AppDomain, another
server, etc...). I am not going to go too much in details but there were 2 ways
to marshal objects in the .net Remoting infrastructure : by reference or by value.
Basically it means you can only marshal remote objects if they are inheriting <code>
MarshalByRef</code> or if they implement <code>ISerializable</code>. Our plan
is not to use the remoting capabilities at all but we still need to let the <code>RealProxy</code>
class think our target is acceptable for remoting. That's why we pass <code>typeof(MarshalByRef)</code>
to the <code>RealProxy</code> base constructor.
</p>
<p>
The <code>RealProxy</code> class is receiving all calls made on the transparent
proxy via the <code>System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage
msg)</code> method. That's where we will implement the details about method
swapping. Read the comments in the code above.
</p>
<p>
About the implementation of <code>IRemotingTypeInfo</code>: In a true remoting environment
the client side would request an object to the server. The client application runtime
might not know anything about the type of the marshalled remote object. So when
the client app makes a call to the method <code>public object GetTransparentProxy()</code>
the runtime must decide if the returned object (the transparent proxy) is boxable
to the client application expected contract. By implementing <code>IRemotingTypeInfo</code>
you give a hint to the client runtime telling if casting to a specified type is
allowed or not.<br />
And guess what the trick is there, in front of your astonished gaze, right here...
</p>
<pre lang="C#">
public bool CanCastTo(Type fromType, object o) { <strong>return true;</strong> } </pre>
<p>
All our AOP implementation is only possible due to the possibility offered by remoting
to write these 2 words: <code>return true;</code> <u>Passed that point we can cast the
object returned by</u> <code>GetTransparentProxy()</code> <u>to whatever interface <b>
without any runtime check!!!</b></u>.
</p>
<p>
The runtime just purely and simply gave us a "yes card" to play with!</p>
<p>
We might want to revisit that code to return something more appropriate than true
to any type... But we could also imagine make use of this behaviour to provide a
<a href="http://haacked.com/archive/2009/08/25/method-missing-csharp-4.aspx">Missing
Method</a> implementation or a catch all interface... There is a lot of room
fot your creativity to express istself here!</p>
<p>
At that point we have a decent interception mechanism for our target instance. We
are still mising interception of constructors and creation of the transparent proxy.
That's a job for a factory...
</p>
<h3>
The Factory</h3>
<p>
Not much to say about that one. Here is the skeleton of the class.</p>
<pre lang="C#">
public static class Factory
{
public static object Create<T>(params object[] constructorArgs)
{
T target;
// TODO:
// Base on typeof(T) and the list of constructorArgs (count and their Type)
// we can ask our Registry if it has a constructor method joinpoint and invoke it
// if the Registry has no constructor joinpoint then simply search for the corresponding one
// on typeof(T) and invoke it...
// Assign the result of construction to the "target" variable
// and pass it to the GetProxy method.
return GetProxyFor<T>(target);
}
public static object GetProxyFor<T>(object target = null)
{
// Here we are asked to intercept calls on an existing object instance (Maybe we constructed it but not necessarily)
// Simply create the interceptor and return the transparent proxy
return new Interceptor(target).GetTransparentProxy();
}
}
</pre>
<p>
Note that the <code>Factory</code> class is always returning an object of type <code>
object</code>. We can't return an object of type <code>T</code> because the
transparent proxy is simply not of type <code>T</code>, it is of type <code>System.Runtime.Remoting.Proxies.__TransparentProxy</code>.
But, remember the "Yes card", <b>we can cast the returned object to whatever interface
without any runtime checking!</b></p>
<p>
We will nest the <code>Factory</code> class in the <code>AOP</code> class hoping
to give a neat programming experience to our consumers. But you'll see that in the
Usage section below</p>
<h2>
Final notes on implementation</h2>
<p>
If you have read the whole article till that point I must recognize you are almost
a hero! Bravissimo! Kudos!
<br />
</p>
<p>
For the sake of brevity and clarity of this article (damned... why are you smiling?)
I am not going to discuss the boring implementation details of method retrievals
and switching. There is actually not much fun in it. But if you are interested in
that piece then you can <b>download the code and browse it : it is fully functional!</b>.
The classes and methods signature might be a bit different as I am coding while
writing the article :-) but no major change is to be expected.</p>
<p style="border-style: solid; border-width: 1px; margin-left: 40px; margin-right: 40px;">
<u><b>Warning</b></u>: <strong>Before deciding to use this code in your project please
read carefully the </strong><a href="http://en.wiktionary.org/wiki/paenultimus"><strong>
paenultimus</strong></a><strong> section. </strong>And if you don't
know the word paenultimus then I guess you have to click the link first :-)
</p>
<h2>
Usage</h2>
<p>
I have been writing a lot but did not give you, yet, a proper hint on how we can
actually use all of this. And finally here we are : the moment of truth!
</p>
<p>
The attached source code is including 5 examples for the sake of demonstration.
Which are injecting an aspect by:</p>
<ul>
<li>Intercepting a constructor</li>
<li>Intercepting methods and properties</li>
<li>Intercepting events</li>
<li>Intercepting type initialization</li>
<li>Intercepting <code>File.ReadAllText(string path)</code></li>
</ul>
<p>
I will demonstrate 2 here, the most and the less obvious</p>
<h3>
The most obvious: Intercepting methods and properties
</h3>
<p>
First we need a domain model... Nothing fancy</p>
<pre lang="C#">
public interface IActor
{
string Name { get; set; }
void Act();
}
public class Actor : IActor
{
public string Name { get; set; }
public void Act()
{
Console.WriteLine("My name is '{0}'. I am such a good actor!", Name);
}
}
</pre>
<p>
Then we need a <b>concern</b></p>
<pre lang="C#">
public class TheConcern : IConcern<Actor>
{
public Actor This { get; set; }
public string Name
{
set
{
This.Name = value + ". Hi, " + value + " you've been hacked";
}
}
public void Act()
{
This.Act();
Console.WriteLine("You think so...!");
}
}
</pre>
<p>
At application initialization we tell the Registry about our <b>joinpoints</b></p>
<pre lang="C#">
// Weave the Name property setter
AOP.Registry.Join
(
typeof(Actor).GetProperty("Name").GetSetMethod(),
typeof(TheConcern).GetProperty("Name").GetSetMethod()
);
// Weave the Act method
AOP.Registry.Join
(
typeof(Actor).GetMethod("Act"),
typeof(TheConcern).GetMethod("Act")
); </pre>
<p>
And finally we create an object via the Factory</p>
<pre lang="C#">
var actor1 = (IActor) AOP.Factory.Create<Actor>();
actor1.Name = "the Dude";
actor1.Act(); </pre>
<p>
Note that we requested the creation of an <code>Actor</code> class but we can cast
the result to an interface so let's use <code>IActor</code> as the class is
implementing it.</p>
<p>
If you run that in a Console application the output will be the following:</p>
<pre>
My name is 'the Dude. Hi, the Dude you've been hacked'. I am such a good actor!
You think so...! </pre>
<h3>
The less obvious: Intercepting <code>File.ReadAllText(string path)</code>
</h3>
<p>
Here we have 2 <i>slight</i> issues:</p>
<ol>
<li>the <code>File</code> class is static</li>
<li>and does not implement any interface</li>
</ol>
<p>
That's where we benefit from the "Yes card"! Remember? There is no runtime type
checking between the returned proxy and the interface.<br />
Which means we can create any kind of interface... no one as to implement it anyway:
neither the <b>target</b> nor the <b>concern</b>. Basically we are only using the
interface as a contract...</p>
<p>
Let's demonstrate that by creating a fake interface to mimic the static <code>File</code>
class</p>
<pre lang="C#">
public interface IFile
{
string[] ReadAllLines(string path);
}
</pre>
<p>
Our <strong>concern</strong></p>
<pre lang="C#">
public class TheConcern
{
public static string[] ReadAllLines(string path)
{
return File.ReadAllLines(path).Select(x => x + " hacked...").ToArray();
}
}
</pre>
<p>
The registering of <b>joinpoints</b>
</p>
<pre>
AOP.Registry.Join
(
typeof(File).GetMethods().Where(x => x.Name == "ReadAllLines" && x.GetParameters().Count() == 1).First(),
typeof(TheConcern).GetMethod("ReadAllLines")
);
</pre>
<p>
And finally execution of the program</p>
<pre>
var path = Path.Combine(Environment.CurrentDirectory, "Examples", "data.txt");
var file = (IFile) AOP.Factory.Create(typeof(File));
foreach (string s in file.ReadAllLines(path)) Console.WriteLine(s);
</pre>
<p>
In this case please note that we can not use the <code>Factory.Create<T></code>
method as static types cannot be used as generic arguments.</p>
<h2>
References</h2>
<p>
In no particular order:</p>
<ul>
<li><a href="http://www.qi4j.org/ten-minutes-intro.html">Tutorials from Qi4j</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/vstudio/scx1w94y(v=vs.100).aspx">
Extending RealProxy</a></li>
<li><a href="http://kozmic.pl/dynamic-proxy-tutorial/">Dynamic Proxy Tutorial (Castle.net)</a></li>
<li><a href="http://www.codeproject.com/Articles/20884/Introducing-the-LinFu-Framework-Part-I-LinFu-Dynam">
LinFu.DynamicProxy: A Lightweight Proxy Generator</a></li>
<li><a href="http://www.codeproject.com/Articles/114178/Add-Aspects-to-Object-Using-Dynamic-Decorator">
Add aspects using Dynamic Decorator</a></li>
<li><a href="http://www.dolittle.com/blogs/einar/archive/2008/02/10/implementing-a-clr-profiler-to-act-as-an-aop-interceptor-part-1.aspx">
Implementing a CLR Profiler to act as an AOP interceptor</a></li>
<li><a href="http://geekswithblogs.net/imilovanovic/archive/2004/09/23/11589.aspx">Intercepting
the .Net</a></li>
<li><a href="http://www.codeproject.com/Articles/42474/AspectF-Fluent-Way-to-Add-Aspects-for-Cleaner-Main">
AspectF Fluent Way to Add Aspects for Cleaner Maintainable Code</a></li>
</ul>
<h2>
Better to come in Episode 2 !!!</h2>
<p>
Mainly we have been able to achieve the primary goal of AOP : implement an aspect
and register it for execution. <u>TinyAOP is born</u>. But there must be an episode
2! We have not finished our journey in AOP land yet:</p>
<ul>
<li>Reason #1: Who wants to register Joinpoints the way we are now? Not me, for sure!
With a bit of introspection we can make things much more practical and build something
that look like a real AOP library. AOP is there to facilitate your life not to introduce
more pain.</li>
<li>Reason #2: I promised to introduce you to <strong>mix-ins</strong> and <strong>composition</strong>.
These matters are still completely uncovered.</li>
<li>Reason #3: We need <u>performance</u> and <u>stability</u>. Now the code is just
a proof of concept ( less than 250 lines of code :-) ). It is far too slow when
we can make it very fast. A bit of error checking would not be bad either.</li>
<li>Reason #4: We are intercepting almost any kind of class but what about <strong>interfaces</strong>
interception?? </li>
<li>Reason #5: Do we really need more reasons ?</li>
</ul>
<p>
<u>Conclusion: </u>We have a nice and tiny prototype which demonstrates the technical
feasability of doing it purely with managed, non-dynamic, code without weaving,
etc... In next episode let's bring that to a production-ready, full featured implementation
! Guys expect some refactoring :-)</p>
<h2>
A few last words, off-topic</h2>
<p>
No secret that I am french... Nobody's perfect! While writing this article I was
googling for a place where the expression "A boire, ou je tue le chien!" would be
explained and I found that page called "French expressions you won't learn at school".
I am sure you might find some of these expressions pretty funny so I am sharing
the link : http://www.globule.org/~gpierre/french.php
<br />
</p>
<br />
<p>
A website such as Codeproject is only working because some guys are writing and
publishing articles. Whatever the reasons why these guys are doing it, they are!
And that takes <b>a non-negligible amount of work and time</b>.
</p>
<p>
Please <b>do not neglect that time and work:</b><br />
If you don't like the article please refrain to give your vote of 1 without further
explanations... I might have wrote a statement which is wrong or false, my english
surely needs rephrasing, maybe you are expecting more or less explanations, I don't
know... It is as simple as that:<b> I don't know if you don't tell! </b>Your <u>justified</u>
bad ratings are welcome I am not gonna hurt (maybe a bit ;-) ) but it will allow
me to revise my judgment, make any necessary adjustments or corrections to the article
and also to improve myself for future ones.</p>
<p>
Now if you liked the article, or you are using the code or if you have learned something
today then <strong>let me know as well</strong> : leave a comment, give me your
vote (of 5 :-)), drop me an email, connect on LinkedIn... Whatever form of feedback
is much appreciated!!!</p>
<p>
Thanks for reading!</p>
</body>
</html>