Archive

About Enterprise Library With the new release of the Enterprise Library of Microsoft patterns & practices team, it seems like AOP makes a great and sudden come back in the .NET community. The latest release comes indeed with the Policy Injection Application Block, which is a kind of AOP framework that allows to "inject" the other Enterprise Library application blocks (logging, exception handling, ...) into user code, and using a configuration file. The implementation use remoting proxies to intercept method calls and inject policies, which has the major drawbacks to:
  • Be limited to methods derived from MarshalByRefObject or exposing their semantics on an interface.
  • Require instances to be created through a factory.
This is a great opportunity to demonstrate how PostSharp can be used, not only to overcome these issues, but also to offer new benefits. Hopefully, the p&p team had this in mind when they designed this application block: the framework can be used even if we choose not to go through factories. About PostSharp PostSharp is a post-compiler for the .NET Framework. It modifies .NET assemblies after compilation. PostSharp works at MSIL level. PostSharp can be used as an Aspect Oriented Programming (AOP) framework, but it is only one possible use. PostSharp Laos is a true AOP framework that does not require any knowledge of MSIL. Developers can react to "event" that happens in the code and can use the standard System.Reflection API. Introducing PostSharp4EntLib The first release of PostSharp4EntLib provides three custom attributes that 'bind' Policy Injection to user code. The InjectPoliciesFromConfiguration custom attribute This attribute can be applied to an assembly. It means that the policy injection settings will be completely processed at compile time. Here is how it is used: [assembly: InjectPoliciesFromConfiguration("CompileTimePolicyInjection.config")] This custom attribute processes matching rules specified in the configuration file and changes the affected methods so that applied policies are effectively invoked at runtime. This custom attribute serves the scenarios where both matching rules and policies are known at compile time. Benefits are:
  • Matching is performed at compile-time, so that runtime execution is faster.
  • Policy Injection configuration does not have to be deployed.
  • As with anything in PostSharp, remoting proxies and factories are not necessary.
The InjectPolicy custom attribute This attribute indicates that a given policy should be injected to a method. The name of this policy should be known at compile-time, but not the content. This custom attribute may be applied to methods: [InjectPolicy("Exception Handling")] public void Close() { ... } The attribute may be multicasted to many methods using wildcards: [assembly: InjectPolicy("Exception Handling", AttributeTargetTypes="MyProject.BusinessLayer.*")] Benefits of this attribute are:
  • There is no CPU-expensive runtime matching.
  • In some scenarios, make it easier to specify which policies should apply to methods (more flexible than the 'Tag' approach of EntLib).
  • As with anything in PostSharp, remoting proxies and factories are not necessary.
The Interceptable custom attribute This custom attribute simply adds the code to make the method 'interceptable', i.e. to make it a possible target of policy injection, without the use of factories. Policies are matched and applied at runtime. Like the InjectPolicy attribute, this one can be applied to methods, either directly either using multicasting: [assembly: Interceptable("Exception Handling", AttributeTargetTypes="MyProject.BusinessLayer.*")] The benefit is of course that policies can be injected on unchanged existing code:
  • no need for factories,
  • not limited to MarshalByRefObject,
  • works also with static methods.
How does it work? As I said in the beginning, PostSharp achieves this result by modifying the assembly after compilation. The best way to see how the code is modified is to use look at the modified code using Roeder's Reflector. Say we have the following user code (in C#): public static void Transfer(BankAccount origin, BankAccount destination, decimal amount) { origin.Withdraw(amount); destination.Deposit(amount); } We make this method interceptable by one of the three custom attributes described above. After compilation and post-processing by PostSharp, the method looks like that: [DebuggerNonUserCode] public static void Transfer(BankAccount origin, BankAccount destination, decimal amount) { Delegate delegate2 = new ~PostSharp~Laos~Implementation.~delegate~3(BankAccountProcess.~Transfer); object[] arguments = new object[] { origin, destination, amount }; MethodInvocationEventArgs eventArgs = new MethodInvocationEventArgs(delegate2, arguments); ~PostSharp~Laos~Implementation.~aspect~9.OnInvocation(eventArgs); } The old method body has been moved to a new (private) method called ~Transfer. The new implementation basically creates a delegate to the old implementation, create event arguments and call a OnInvocation method. This is where the PostSharp4EntLib code lays. Basically, this method invokes the EntLib pipeline of handlers. The implementation of PostSharp4EntLib has two parts:
  • A compile-time part whose principal role is to detect which methods needs to be 'interceptable', and adds kinds of 'event handlers' (OnMethodInvocation in our case) on these methods.
  • A runtime part which is basically the implementation of the event handlers.
I repeat, PostSharp4EntLib does not generate MSIL instructions itself. It relies on PostSharp Laos, which defines this system of "code-driven event handlers" whose OnMethodInvocation is the only used here. Other "handlers" (called aspects or advices) are OnMethodBoundary, OnFieldAccess or OnException. They are not currently used but may be in the future of this project. Waiting for a CodePlex project... I would like to release this project on CodePlex but I am still waiting for Microsoft to upgrade their servers. Would you have any influence on the acceptance on my project... ;-) Before I get the CodePlex space, you can access the project from the PostSharp4EntLib Project Dashboard. Many thanks to Olaf Conijn for its online support.
According to Ohloh, it would cost 15 man-years to develop PostSharp from scratch by a team of professionals and the source code would have a value of 800 000 $. Amazing! I've started PostSharp in September 2004 and have programmed mainly in my spare time. Right, that's a lot of time. Ask my wife how it is to live with a passionated developer. But anyway, it hardly reaches 15 hours per week in the average. How to understand this difference in order of magnitude of 1 to 10? First, notice that it is not exceptional in open-source projects. Compare with other projects and you will see. What is maybe uncommon in PostSharp, it is the complexity of the problem. But even this statement may be pure vanity. So why a lot of open-source projects are 10 times more productive than commercial ones? I see a lot of factors. When working on PostSharp:
  • I don't take long coffee pauses neither read online newspapers.
  • I don't attend meaningless meetings.
  • I don't have to negotiate every design detail with doubtfully competent colleagues.
  • Business stakeholder don't change their mind every Monday.
  • I don't care writing analysis and design documents before coding.
  • ...
So if these estimates are really relevant in business context, the real question is why is software development so little productive in business environment?
I had a new interesting discussion, this time with John Vanspronssen. I'm not sure I've understood all he has in mind, but I was challenged by the idea of 'composed aspects', that is, aspects composed of many transformations. In order to avoid confusion with object composition, I chose to rename this combined aspects. I first planned to implement this in a later phase, but this discussion just excited me to do it... and it's done! So what's a composed aspect? As I said, it is an aspect composed of many sub-aspects. John gave the binding aspect as an example. This aspect 'simply' raises an event OnPropertyChanged. Say I have the following base code:
interface IBindable
{
event EventHandler OnPropertyChanged;
}

[Bindable]
class MyClass
{
private int field1;

public int Field1
{
 get { return field1; }
 set { field1 = value; }
}
}
The post-compiled code should look like this:
class MyClass : IBindable
{
private int field1;

public event EventHandler OnPropertyChanged;

public int Field1
{
  get { return field1; }
  set
  {
      field1 = value;
      if (this.OnPropertyChanged != null)
      {
          this.OnPropertyChanged(this, EventArgs.Empty);
      }
  }
}
}
There are two sub-aspects combined in the Binding aspect:
  1. A CompositionAspect: adding the IBinding interface and its implementation.
  2. An OnMethodBoundaryAspect applied to the method set_MyProperty method: raising the OnPropertyChanged method. If there were more than one property, there would be one aspect of this type for each writable property.
The aspect implementation has less than 100 lines of code including blank ones. I don't copy it in this post, but you can see it online. The following points are interesting:
  1. The class BindableImplementation is the implementation of the IBindable interface. This type is composed inside the target the AddBindableInterfaceAspect aspect, which is derived from CompositionAspect.
  2. The aspect OnPropertySetAspect is derived from OnMethodBoundaryAspect and implements only the OnExit method. The only thing it does is to retrieve the implementation of IBindable for this instance (that is, the composed BindableImplementation object) and raise the OnObjectChanged event.
  3. The class BindableAttribute is the principal class and the only public one. It is derived from CombinedAspect and implement the method ProvideAspects. This method is the most interesting. First it adds the AddBindableInterfaceAspect to the type, then it scans all the writable properties in this type and applies the OnPropertySetAspect to them. This method is of course executed at compile time.
A good question is: how can the OnProperySetAspect retrieve the implementation of the IBindable interface? It took me at least two nights to answer. Let me ask the question more formally: suppose that an object is composed of different behaviours (composed objects and aspects). How can these different behaviour exchange information between themselves? I think that this problem should ideally be solved by the platform, that is, by .NET itself. The platform should ideally have a concept that 'an instance is the friend of another'. If the developer chooses to apply an aspect to a class, it is legitimate to give this aspect more permissions on the target type than the permissions we want to give to everybody ('public' access). And it is not possible for the aspect to have access only to protected data, since the aspect is not derived from the target type. The solution I designed is to rely on credentials. Each instance (at least each instance of a type that wants to 'share' something) has its own 'secret' called credentials. The can give the credentials to some other instance. Then, this instance can use these credentials to get access to some 'protected' data (but here protected by these credentials, not by restriction of visibility). This mechanism is currently only used to retrieve the instance implementing an interface that has been composed by CompositionAspect. Composed types may optionally implement the interface IComposed , where T is the composed interface (IBindable in our example). This interface has a single method GetImplementation... that requires the credentials. How can the OnPropertySetAspect know the credentials? These are passed through the event arguments (MethodExecutionEventArgs). That is, aspects will receive the credentials to access 'protected' data of the aspected instance. But only of this instance! I've said this was designed, but this is not completely implemented. In the version I put online tonight, credentials are not yet checks. And there are still problems if you try to apply the same custom attributes on a class and its parent class. This will be solved during the next week or two. Enjoy! Gael