PostSharp4EntLib

Vision Statement

PostSharp4EntLib combines the benefits of the Enterprise Library Policy Injection and of compile-time weaving by removing the limitations due to the use of remoting proxies.

Project Description

The Microsoft Enterprise Library offers many application blocks that can typically be used in aspect-oriented scenarios. The new Policy Injection Application Block (PIAB) even allows policies such as logging, exception handling or security to be 'injected' at runtime in existing methods.

The official implementation of PIAB relies on transparent proxies. The major drawback of this approach is that it requires intercepted classes (1) to be derived from MarshalByRefObject or to expose their complete semantics on an interface and (2) to be instantiated using the PIAB proxy.

The objective of this project is to unveil the power of the Enterprise Library in aspect-oriented (or policy injection) scenarios by removing the limitations bound to transparent proxies.

To achieve this, we use PostSharp Laos, a post-compiler and AOP suite for the .NET Framework. As its name indicates, PostSharp post-processes .NET assemblies after compilation.

Installation

You need to install PostSharp on each development machine in order to build projects using PostSharp4EntLib (including the sample project). PostSharp does not need to be deployed on users' machines. You need the version 1.0 Beta 2 or greater.

Documentation

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 four kinds of 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.

AuthorizationCallHandler, CachingCallHandler, ExceptionCallHandler, LogCallHandler and ValidationCallHandler

These four custom attributes explicitely specify that a call handler should be added to the method. These custom attributes are defined standardly by PIAB and defined in the namespace Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers. PostSharp4EntLib redefines them in the namespace PostSharp4EntLib.PolicyInjection. Why defining new attributes? To profit from the multi-casting features of PostSharp Laos. It would also be possible to weave only based on the original PIAB custom attributes (but this is not implemented).

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 ab 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.

Last edited Dec 15, 2009 at 12:18 PM by ewdev, version 6

Comments

mfreidge Feb 18, 2012 at 6:53 PM 
Is it compatible with EntLib v5 ?