Jonathan George's Blog

Make methods “fire and forget” with PostSharp

Posted in Technical Stuff by Jonathan on September 10, 2009

Note: This was originally posted on my old blog at the EMC Consulting Blogs site.

Since I first encountered it a year or so ago, I’ve been dabbling with PostSharp, an Aspect Oriented Programming framework for .NET. In a recent blog post, Howard mentioned it and showed an aspect that can be used to remove a whole load of the boilerplate code required to implement the INotifyPropertyChanged interface. Whilst he was good enough to name check me for the creation of that code, I’ll ‘fess up now and admit that I didn’t write it myself – I picked it up from Pete Weissbrod’s blog and put it into a form where I could use it to hijack a conversation taking place on one of our internal mailing lists. If you want to get hold of that code and have a look, then you can get hold of the aspect plus tests from Codeplex.

We’ve started to build up a library of aspects to cover various things common to a lot of projects, for example caching and performance monitoring. I’m planning on writing about these over the coming weeks/months, but I thought it would be sensible to start with the most straightforward.

I recently came across a situation where I wanted to make a method “fire and forget” – i.e. I didn’t need a return value, and I didn’t want it to block execution of subsequent code. This is the kind of code you’d probably write to achieve that.

  1. class FireAndForgetWithoutPostsharp
  2. {
  3.     public void MySynchronousMethod(string argument)
  4.     {
  5.         ThreadPool.QueueUserWorkItem(
  6.             this.MySynchronousMethodInternal,
  7.             argument);
  8.     }
  9.     private void MySynchronousMethodInternal(object state)
  10.     {
  11.         var argument = state as string;
  12.         // Do the work…
  13.     }
  14. }

This code isn’t great, because the fact that we’re making the method non-blocking makes it more complex and obscures its real purpose. Enter PostSharp and this sample code from the homepage:

  1. public class AsyncAttribute : OnMethodInvocationAspect
  2. {
  3.     public override void OnInvocation(
  4.         MethodInvocationEventArgs eventArgs)
  5.     {
  6.         ThreadPool.QueueUserWorkItem(
  7.             delegate { eventArgs.Proceed(); });
  8.     }
  9. }

Suddenly, you can drop all the boilerplate from the first sample, and you end up with this:

  1. class FireAndForgetWithPostsharp
  2. {
  3.     [Async]
  4.     public void MyMethod(string argument)
  5.     {
  6.         // Do the work
  7.     }
  8. }

Clearly this is much nicer – there’s nothing getting in the way of understanding what the code is supposed to be doing, and you can instantly see that the method will actually be non-blocking because of the attribute.

The async attribute is implemented using the OnMethodInvocationAspect base class from the PostSharp.Laos namespace. When the PostSharp weaver runs, it renames your original method and replaces it with a new method. This calls the OnInvocation method of your the aspect, passing a MethodInvocationEventArgs object which contains (amongst other things) the arguments passed to your method, the return value, and a Delegate pointing back to your renamed original method. It also has the Proceed() method which is used to invoke the original method.

Shortly after I implemented this in my web application, I noticed some odd behaviour when the site was under heavy load. Some digging turned up a school of thought which says that using ThreadPool.QueueUserWorkItem in a high traffic web app (which coincidentally is what I’m working on) is not a great idea – see Mads Kristensen’s article or this post on StackOverflow. I decided to switch to an alternative method, and modified the aspect to allow it to use one of three asynchronous invocation methods:

  • ThreadPool.QueueUserWorkItem.
  • Calling BeginInvoke on a delegate.
  • Creating a new background thread.

The aspect code now looks like this.

  1. public class AsynchronousAttribute : OnMethodInvocationAspect
  2. {
  3.     public AsynchronousAttribute()
  4.         : this(AsynchronousInvocationOption.ThreadPool)
  5.     {
  6.     }
  7.     public AsynchronousAttribute(AsynchronousInvocationOption invocationOption)
  8.     {
  9.         this.InvocationOption = invocationOption;
  10.     }
  11.     public AsynchronousInvocationOption InvocationOption { get; set; }
  12.     public override void OnInvocation(MethodInvocationEventArgs eventArgs)
  13.     {
  14.         switch (this.InvocationOption)
  15.         {
  16.             case AsynchronousInvocationOption.BackgroundThread:
  17.                 this.InvokeUsingBackgroundThread(eventArgs);
  18.                 break;
  19.             case AsynchronousInvocationOption.Delegate:
  20.                 this.InvokeUsingDelegate(eventArgs);
  21.                 break;
  22.             default:
  23.                 this.InvokeUsingThreadPool(eventArgs);
  24.                 break;
  25.         }
  26.     }
  27.     private void InvokeUsingBackgroundThread(MethodInvocationEventArgs eventArgs)
  28.     {
  29.         var thread = new Thread(eventArgs.Proceed)
  30.         {
  31.             IsBackground = true
  32.         };
  33.         thread.Start();
  34.     }
  35.     private void InvokeUsingDelegate(MethodInvocationEventArgs eventArgs)
  36.     {
  37.         var proceed = new Action(eventArgs.Proceed);
  38.         proceed.BeginInvoke(proceed.EndInvoke, proceed);
  39.     }
  40.     private void InvokeUsingThreadPool(MethodInvocationEventArgs eventArgs)
  41.     {
  42.         ThreadPool.QueueUserWorkItem(delegate { eventArgs.Proceed(); });
  43.     }
  44. \

As you can see, I have a new property, set via a constructor argument, that allows the user to specify the way in which their method is made asynchronous.

  1. class FireAndForgetWithPostsharp
  2. {
  3.     [Asynchronous(AsynchronousInvocationOption.Delegate)]
  4.     public void MyMethod(string argument)
  5.     {
  6.         // Do the work
  7.     }
  8. }

Disclaimer: Before using this in anger, you need to make sure you’re aware of the implications of invoking methods asynchronously. A couple of gotchas you may spot are:

  • Any exceptions which are thrown by the method are swallowed, as there’s nothing to handle them. Therefore when making a method fire-and-forget, ensure you add a try-catch block in to do any necessary logging/clean up and prevent the exception taking your app down.
  • Threads created as background threads die with the app. So if you fire off an operation on a background thread in your console app, and that app then exits, the operation may not complete. Ultimately, there’s no way to guarantee 100% that your method will run when using this approach – so only use it if you can accept this risk. If you need guaranteed execution then there are various ways of achieving it, ranging from the simple (use of AutoResetEvent) to the full-on message queue based solution.

Whilst I find Postsharp aspects to be very useful, it’s worth making the point that (like a lot of things in software development) the Pareto principle applies. In all likelihood, a relatively basic aspect implementation will cover the majority of your requirements, and the rest can be covered by custom code as needed, so there’s no need to try and make the aspect cover every eventuality

You can download the code, with unit tests to prove that it really is doing what it should, from Codeplex.

Aspects I’m currently planning to cover in future posts are (listed in increasing order of complexity):

  • TimeOut – Another simple one, this allows a timeout period to be specified for any method and causes a TimeoutException to be thrown if the method execution time exceeds that period.
  • Performance monitoring – Aspects to time and count method executions and write to Windows performance counters.
  • Caching – Caches the results of a method call. There’s a basic example of this on the Postsharp site, but it doesn’t cover how to generate appropriate cache keys.
  • Logging – Adds entry and exit logging to methods. I’m hoping to persuade James to break off from his Agile/MVC/BDD blogging and write this one up, since he wrote the one in our core library.

If you find this interesting and/or useful, please leave me a comment or rate this article.


Tagged with: ,