By now we all have heard of postsharp. By now we would have all used it once or twice or we would be using it on daily basis now. I am not going to go into what postsharp does since you can read all about here. But what’s more important to me was understanding what it facilitates.
Scenario
So let’s say you get so far down a project and decide you want global exception handling and logging applied to your application. Kind of what the exception handling & logging application blocks do together with policy injection. So now you want to supply that functionality with the least impact possible to your code, deadlines and other constraints.
Policy Injection – Enterprise Library
So what impact would we have with policy injection. Well first of all we have to have the following assumptions:
Our classes need to implement an interface OR Our classes need to inherit from MarshalByRefObject
Now that in itself is very limiting because we cannot guarantee such a requirement but let’s take an optimistic step and say that the requirement is sufficed. We now have to go into every class’s instantiation and use the policy injection application block’s wrap or create method. But that’s a lot of impact on the code if we are working on an application with a decently sized object model or too many operations. So how’s postsharp better.
PostSharp – Injection with power
So with postsharp we create these things called aspects. So for the scenario above we would create two aspects one for exception handling and one for logging. To make this interesting let’s say we want to you use the exception handling application block to handle the exceptions and log any exceptions to a text file called trace.log. For the logging we want to just write to the console.
I start of by creating an aspects project in my solution (optional).
I then reference the necessary PostSharp assemblies, PostSharp.Public & PostSharp.Laos.
My Exception aspect would look something like this after inheriting from the base OnExceptionAspect base class from the PostSharp library.
using System; using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling; using PostSharp.Laos; namespace PostSharpDemo.Aspects { /// <summary> /// This is a test exception aspect that will be injected into /// the business project. The aspect catches any unhandled /// exceptions and uses the exception handling application block /// to handle the exception. /// </summary> [Serializable] public sealed class MyExceptionAspect : OnExceptionAspect { public override void OnException(MethodExecutionEventArgs eventArgs) { bool rethrow = ExceptionPolicy.HandleException(eventArgs.Exception, "Demo Exception Policy"); if (rethrow) { Console.WriteLine(eventArgs.Exception.Message); Console.WriteLine("Exception being handled by aspect!"); } } } }
and my logging aspect would looks as follows
using System; using PostSharp.Laos; namespace PostSharpDemo.Aspects { /// <summary> /// This aspct is defined to demo tracing capability /// with postsharp usage in AOP. /// </summary> [Serializable] public class MyOnMethodInvocationAspect : OnMethodInvocationAspect { public override void OnInvocation(MethodInvocationEventArgs context) { Console.WriteLine("Calling {0}", context.Delegate.Method); context.Proceed(); } } }
That’s it for our project. It’s as simple as that. Now how do we use this with our target assembly i.e. how do we inject those aspects? We first of all reference the assembly and the PostSharp assemblies again.
and for the final piece of the puzzle we place the following couple of lines in our assembly.info (or any other file in the project really).
// by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] //PostSharp assembly injection. [assembly: MyExceptionAspect(AttributeTargetAssemblies = "PostSharpDemo.Business", AttributeTargetTypes = "PostSharpDemo.Business.*")] [assembly: MyOnMethodInvocationAspect(AttributeTargetAssemblies = "PostSharpDemo.Business", AttributeTargetTypes = "PostSharpDemo.Business.*")]
Build, run and voila every single method executed within the assembly is traced to the console and any unhandled exception will be directed at the Exception Handling Application block for policy processing.
The demo solution can be downloaded here.
I hope at this stage you are already happy with the possibilities. But wait there is more.
PostSharp bundled with PIAB
So is the policy injection application block useless now. Absolutely not. It still has it’s place and I see even the bigger potential is to treat both tools as power tools to be used in the correct scenarios. My wondering brain made me think of the possibility of using PostSharp to apply policy injection on all the classes in an assembly just to find out that this has already been thought of. You can find the project PostSharp4Entlib at http://www.codeplex.com/entlibcontrib/Wiki/View.aspx?title=PostSharp4EntLib&referringTitle=Home
Now how is this so special? Well two things:
- PolicyInjection now will happen at compile time not at run time, so there is a significant gain in performance including the fact that you wouldn’t need to have the PIAB configuration section in the configuration file at runtime anymore. Note: you still need the configuration sections for the other application blocks.
- The limitation of having the classes implement an interface or inherit from MarshalByRefObject is now gone, since we don’t need any runtime injection to the objects.
There was one issue though. The project on codeplex had a lot of build errors regarding assembly versions etc. I took the liberty of combining the newest pieces, PostSharp 1.0 Sp1, Entlib 4.0 & PostSharp4Entlib and building my own little solution while fixing all the build errors. I also came up with a little sample demo to demonstrate the usage of the library. So now one line of code in AssemblyInfo.cs
[assembly: InjectPoliciesFromConfiguration("Entlib.config")]results in the same effect that would have had to cost me instantiating or wrapping every class using policy injection or having the limitation on the objects having to inherit or implement interfaces or other classes.
A PostSharpForEntlib updated project and a demo can be downloaded here.
I hope this has been useful. Happy Injection! :)