This is part 3 of my series of posts on using AspectMap – an aspect oriented framework for StructureMap. If you’re new to AspectMap I’d recommend starting at the beginning and working through the series:

In this post we’ll create a retry aspect which will allow you to retry the functionality of a method a specified number of times for a certain exception. For instance you could set a method up to try some SQL operation up to 4 times if it receives timeout exceptions. This will introduce you to the technique for inspecting the attribute that kicked off your handler.

We’ll start with the attribute:

public class RetryAttribute : Attribute
{
  public RetryAttribute(int maxTries, Type targetException)
  {
    MaxTries = maxTries;
    TargetException = targetException;
  }

  public int MaxTries { get; set; }
  public Type TargetException { get; set; }
}

Notice that it has two properties, populated through the constructor. TargetException is the exception which will trigger a retry, and MaxTries is the maximum number of attempts that will be made. This would be specified on a method like this:

[Retry(3, typeof(TimeoutException))]
public void CompleteLongRunningOperation()
{
  // Long running code which could throw a TimeoutException
}

So this will allow two retries of a TimeoutException before finally throwing it. Any other exception will be thrown as usual.

So, how do we implement the handler? Create a new RetryAttributeHandler inheriting from AttributeHandler and put the following code into its Surround method:

if (!(sourceAttribute is RetryAttribute))
  throw new ArgumentException("Unable to handle retries for attribute '" +
    sourceAttribute.GetType() + "'.");

RetryAttribute attribute = (RetryAttribute)sourceAttribute;

Fairly simple, we only want to deal with RetryAttributes. Next comes the important bit:

return i =>
{
  for (int count = 1; count <= attribute.MaxTries; count++)
  {
    try
    {
      invocation(i);
      return;
    }
    catch (Exception ex)
    {
      if (ex.GetType() != attribute.TargetException ||
                   count == attribute.MaxTries)
        throw;
    }
  }
};

We loop until MaxTries, and if an exception is thrown we check if we are on the last try, or the exception is not of the expected type. If so we throw it, otherwise we continue around the loop. The return statement ensures that if invocation(i) run’s successfully that we don’t continue round and do it again!

That’s pretty much it, you wire up your registry just like we did in previous posts:

ForAspect<RetryAttribute>().HandleWith<RetryAttributeHandler>();
For<ITestClass>().Use<MyClass>().EnrichWith(AddAspectsTo<ITestClass>);

One thing which I hope is becoming clear now is that there never seems to be much actual code involved – if you can think of a concern cross cutting enough, it will generally be generic enough to make the coding of it trivial. Which I see as a great thing!

Next up I’ll discuss nesting and prioritisation of handlers, at which point you’ll have all the major skills you need to go out and start creating some really funky stuff. Thanks for reading!