Chapter 17. AOP Guide

17.1. Introduction

This is an introductory guide to Aspect Oriented Programming (AOP) with Spring.NET.

This guide assumes little to no prior experience of having used Spring.NET AOP on the part of the reader. However, it does assume a certain familiarity with the terminology of AOP in general. It is probably better if you have read (or at least have skimmed through) the AOP section of the reference documentation beforehand, so that you are familiar with a) just what AOP is, b) what problems AOP is addressing, and c) what the AOP concepts of advice, pointcut, and joinpoint actually mean... this guide spends absolutely zero time defining those terms. Having said all that, if you are the kind of developer who learns best by example, then by all means follow along... you can always consult the reference documentation as the need arises (see Section 9.1.1, “AOP concepts”).

The examples in this guide are intentionally simplistic. One of the core aims of this guide is to get you up and running with Spring.NET's flavor of AOP in as short a time as possible. Having to comprehend even a simple object model in order to understand the AOP examples would not be conducive to learning Spring.NET AOP. It is left as an exercise for the reader to take the concepts learned from this guide and apply them to his or her own code base. Again, having said all of that, this guide concludes with a number of cookbook-style AOP 'recipes' that illustrate the application of Spring.NET's AOP offering in a real world context; additionally, the Spring.NET reference application contains a number of Spring.NET AOP aspects particular to it's own domain model (see Chapter 19, SpringAir - Reference Application).

17.2. The basics

This initial section introduces the basics of defining and then applying some simple advice.

17.2.1. Applying advice

Lets see (a very basic) example of using Spring.NET AOP. The following example code simply applies advice that writes the details of an advised method call to the system console. Admittedly, this is not a particularly compelling or even useful application of AOP, but having worked through the example, you will then hopefully be able to see how to apply your own custom advice to perform useful work (transaction management, auditing, security enforcement, thread safety, etc).

Before looking at the AOP code proper lets quickly look at the domain classes that are the target of the advice (in Spring.NET AOP terminology, an instance of the following class is going to be the advised object.

    public interface ICommand 
    {
        object Execute(object context);
    }
    
    public class ServiceCommand : ICommand
    {
        public object Execute(object context)
        {
            Console.Out.WriteLine("Service implementation : [{0}]", context);
            return null;
        }
    }

Find below the advice that is going to be applied to the object Execute(object context) method of the ServiceCommand class. As you can see, this is an example of around advice (see Section 9.3.2, “Advice types”).

    public class ConsoleLoggingAroundAdvice : IMethodInterceptor
    {
        public object Invoke(IMethodInvocation invocation)
        {
            Console.Out.WriteLine("Advice executing; calling the advised method..."); 1
            object returnValue = invocation.Proceed(); 2 3
            Console.Out.WriteLine("Advice executed; advised method returned " + returnValue); 4
            return returnValue; 5
        }
    }
1 Some simple code that merely prints out the fact that the advice is executing.
2 The advised method is invoked.
3 The return value is captured in the returnValue variable.
4 The value of the captured returnValue is printed out.
5 The previously captured returnValue is returned.

So thus far we have three artifacts: an interface (ICommand); an implementation of said interface (ServiceCommand); and some (trivial) advice (encapsulated by the ConsoleLoggingAroundAdvice class). All that remains is to actually apply the ConsoleLoggingAroundAdvice advice to the invocation of the Execute() method of the ServiceCommand class. Lets look at how to effect this programmatically...

    ProxyFactory factory = new ProxyFactory(new ServiceCommand());
    factory.AddAdvice(new ConsoleLoggingAroundAdvice());
    ICommand command = (ICommand) factory.GetProxy();
    command.Execute("This is the argument");

The result of executing the above snippet of code will look something like this...

    Advice executing; calling the advised method...
    Service implementation : [This is the argument]
    Advice executed; advised method returned 

The output shows that the advice (the Console.Out statements from the ConsoleLoggingAroundAdvice was applied around the invocation of the advised method.

So what is happening here? The fact that the preceding code used a class called ProxyFactory may have clued you in. The constructor for the ProxyFactory class took as an argument the object that we wanted to advise (in this case, an instance of the ServiceCommand class). We then added some advice (a ConsoleLoggingAroundAdvice instance) using the AddAdvice() method of the ProxyFactory instance. We then called the GetProxy() method of the ProxyFactory instance which gave us a proxy... an (AOP) proxy that proxied the target object (the ServiceCommand instance), and called the advice (a single instance of the ConsoleLoggingAroundAdvice in this case). When we invoked the Execute(object context) method of the proxy, the advice was 'applied' (executed), as can be seen from the attendant output.

The following image shows a graphical view of the flow of execution through a Spring.NET AOP proxy.

One thing to note here is that the AOP proxy that was returned from the call to the GetProxy() method of the ProxyFactory instance was cast to the ICommand interface that the ServiceCommand target object implemented. This is very important... currently, Spring.NET's AOP implementation mandates the use of an interface for advised objects. In short, this means that in order for your classes to leverage Spring.NET's AOP support, those classes that you wish to use with Spring.NET AOP must implement at least one interface. In practice this restriction is not as onerous as it sounds... in any case, it is generally good practice to program to interfaces anyway (support for applying advice to classes that do not implement any interfaces is planned for a future point release of Spring.NET AOP).

The remainder of this guide is concerned with fleshing out some of the finer details of Spring.NET AOP, but basically speaking, that's about it.

As a first example of fleshing out one of those finer details, find below some Spring.NET XML configuration that does exactly the same thing as the previous example; it should also be added that this declarative style approach to Spring.NET AOP is preferred to the programmatic style.

    <object id="consoleLoggingAroundAdvice"
            type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"/>
    <object id="myServiceObject" type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="target">
            <object id="myServiceObjectTarget"
                type="Spring.Examples.AopQuickStart.ServiceCommand"/>
        </property>
        <property name="interceptorNames">
            <list>
                <value>consoleLoggingAroundAdvice</value>
            </list>
        </property>
    </object>
    ICommand command = (ICommand) ctx["myServiceObject"];
    command.Execute();

Some comments are warranted concerning the above XML configuration snippet. Firstly, note that the ConsoleLoggingAroundAdvice is itself a plain vanilla object, and is eligible for configuration just like any other class... if the advice itself needed to be injected with any dependencies, any such dependencies could be injected as normal.

Secondly, notice that the object definition corresponding to the object that is retrieved from the IoC container is a ProxyFactoryObject. The ProxyFactoryObject class is an implementation of the IFactoryObject interface; IFactoryObject implementations are treated specially by the Spring.NET IoC container... in this specific case, it is not a reference to the ProxyFactoryObject instance itself that is returned, but rather the object that the ProxyFactoryObject produces. In this case, it will be an advised instance of the ServiceCommand class.

Thirdly, notice that the target of the ProxyFactoryObject is an instance of the ServiceCommand class; this is the object that is going to be advised (i.e. invocations of its methods are going to be intercepted). This object instance is defined as an inner object definition... this is the preferred idiom for using the ProxyFactoryObject, as it means that other objects cannot acquire a reference to the raw object, but rather only the advised object.

Finally, notice that the advice that is to be applied to the target object is referred to by its object name in the list of the names of interceptors for the ProxyFactoryObject's interceptorNames property. In this particular case, there is only one instance of advice being applied... the ConsoleLoggingAroundAdvice defined in an object definition of the same name. The reason for using a list of object names as opposed to references to the advice objects themselves is explained in the reference documentation...

'... if the ProxyFactoryObject's singleton property is set to false, it must be able to return independent proxy instances. If any of the advisors is itself a prototype, an independent instance would need to be returned, so it is necessary to be able to obtain an instance of the prototype from the context; holding a reference isn't sufficient.'

17.2.2. Using Pointcuts - the basics

The advice that was applied in the previous section was rather indiscriminate with regard to which methods on the advised object were to be advised... the ConsoleLoggingAroundAdvice simply intercepted all methods (that were part of an interface implementation) on the target object.

This is great for simple examples and suchlike, but not so great when you only want certain methods of an object to be advised. For example, you may only want those methods beginning with 'Start' to be advised; or you may only want those methods that are called with specific runtime argument values to be advised; or you may only want those methods that are decorated with a Lockable attribute to be advised.

The mechanism that Spring.NET AOP uses to discriminate about where advice is applied (i.e. which method invocations are intercepted) is encapsulated by the IPointcut interface (see Section 9.2, “Pointcuts in Spring.NET”). Spring.NET provides many out-of-the-box implementations of the IPointcut interface... the implementation that is used if none is explicitly supplied (as was the case with the first example) is the canonical TruePointcut : as the name suggests, this pointcut always matches, and hence all methods that can be advised will be advised.

So let's change the configuration of the advice such that it is only applied to methods that contain the letters 'Do'. We'll change the ICommand interface (and it's attendant implementation) to accomodate this...

    public interface ICommand 
    {
        void Execute();

        void DoExecute();
    } 

    public class ServiceCommand : ICommand
    {
        public void Execute()
        {
            Console.Out.WriteLine("Service implementation : Execute()...");
        }

        public void DoExecute()
        {
            Console.Out.WriteLine("Service implementation : DoExecute()...");
        }
    }

Please note that the advice itself (encapsulated within the ConsoleLoggingAroundAdvice class) does not need to change; we are changing where this advice is applied, and not the advice itself.

Programmatic configuration of the advice, taking into account the fact that we only want methods that contain the letters 'Do' to be advised, looks like this...

    ProxyFactory factory = new ProxyFactory(new ServiceCommand());
    factory.AddAdvisor(new DefaultPointcutAdvisor(
        new SdkRegularExpressionMethodPointcut("Do"),
        new ConsoleLoggingAroundAdvice()));
    ICommand command = (ICommand) factory.GetProxy();
    command.DoExecute();

The result of executing the above snippet of code will look something like this...

    Intercepted call : about to invoke next item in chain...
    Service implementation...
    Intercepted call : returned

The output indicates that the advice was applied around the invocation of the advised method, because the name of the method that was executed contained the letters 'Do'. Try changing the pertinent code snippet to invoke the Execute() method, like so...

    ProxyFactory factory = new ProxyFactory(new ServiceCommand());
    factory.AddAdvisor(
        new DefaultPointcutAdvisor(
            new SdkRegularExpressionMethodPointcut("Do"),
            new ConsoleLoggingAroundAdvice()));
    ICommand command = (ICommand) factory.GetProxy();

    // note that there is no 'Do' in this method name
    command.Execute();

Run the code snippet again; you will see that the advice will not be applied : the pointcut is not matched (the method name does not contain the letters 'Do'), resulting in the following (unadvised) output...

Service implementation...

XML configuration that accomplishes exactly the same thing as the previous programmatic configuration example can be seen below...

    <object id="consoleLoggingAroundAdvice"
        type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor">
        <property name="pattern" value="Do"/>
        <property name="advice">
            <object type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"/>
        </property>
    </object>
    <object id="myServiceObject"
            type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="target">
            <object id="myServiceObjectTarget"
                type="Spring.Examples.AopQuickStart.ServiceCommand"/>
        </property>
        <property name="interceptorNames">
            <list>
                <value>consoleLoggingAroundAdvice</value>
            </list>
        </property>
    </object>

You'll will perhaps have noticed that this treatment of pointcuts introduced the concept of an advisor (see Section 9.4, “Advisors in Spring.NET”). An advisor is nothing more the composition of a pointcut (i.e. where advice is going to be applied), and the advice itself (i.e. what is going to happen at the interception point). The consoleLoggingAroundAdvice object defines an advisor that will apply the advice to all those methods of the advised object that match the pattern 'Do' (the pointcut). The pattern to match against is supplied as a simple string value to the pattern property of the RegularExpressionMethodPointcutAdvisor class.

17.3. Going deeper

The first section should (hopefully) have demonstrated the basics of firstly defining advice, and secondly, of choosing where to apply that advice using the notion of a pointcut. Of course, there is a great deal more to Spring.NET AOP than the aforementioned single advice type and pointcut. This section continues the exploration of Spring.NET AOP, and describes the various advice and pointcuts that are available for you to use (yes, there is more than one type of advice and pointcut).

17.3.1. Other types of Advice

The advice that was demonstrated and explained in the preceding section is what is termed 'around advice'. The name 'around advice' is used because the advice is applied around the target method invocation. In the specific case of the ConsoleLoggingAroundAdvice advice that was defined previously, the target was made available to the advice as an IMethodInvocation object... a call was made to the Console class before the target was invoked, and a call was made to the Console class after the target method invocation was invoked. The advice surrounded the target, one could even say that the advice was totally 'around' the target... hence the name, 'around advice'.

'around advice' provides one with the opportunity to do things both before the target gets a chance to do anything, and after the target has returned: one even gets a chance to inspect (and possibly even totally change) the return value.

Sometimes you don't need all that power though. If we stick with the example of the ConsoleLoggingAroundAdvice advice, what if one just wants to log the fact that a method was called? In that case one doesn't need to do anything after the target method invocation is to be invoked, nor do you need access to the return value of the target method invocation. In fact, you only want to do something before the target is to be invoked (in this case, print out a message to the system Console detailing the name of the method). In the tradition of good programming that says one should use only what one needs and no more, Spring.NET has another type of advice that one can use... if one only wants to do something before the target method invocation is invoked, why bother with having to manually call the Proceed() method? The most expedient solution simply is to use 'before advice'.

17.3.1.1. Before advice

'before advice' is just that... it is advice that runs before the target method invocation is invoked. One does not get access to the target method invocation itself, and one cannot return a value... this is a good thing, because it means that you cannot inadvertently forget to call the Proceed() method on the target, and it also means that you cannot inadvertently forget to return the return value of the target method invocation. If you don't need to inspect or change the return value, or even do anything after the successful execution of the target method invocation, then 'before advice' is just what you need.

'before advice' in Spring.NET is defined by the IMethodBeforeAdvice interface in the Spring.Aop namespace. Lets just dive in with an example... we'll use the same scenario as before to keep things simple. Let's define the 'before advice' implementation first.

    public class ConsoleLoggingBeforeAdvice : IMethodBeforeAdvice
    {
        public void Before(MethodInfo method, object[] args, object target)
        {
            Console.Out.WriteLine("Intercepted call to this method : " + method.Name);
            Console.Out.WriteLine("    The target is               : " + target);
            Console.Out.WriteLine("    The arguments are           : ");
            if(args != null)
            {
                foreach (object arg in args)
                {
                    Console.Out.WriteLine("\t: " + arg);
                }
            }
        }
    }

Let's apply a single instance of the ConsoleLoggingBeforeAdvice advice to the invocation of the Execute() method of the ServiceCommand. What follows is programmatic configuration; as you can see, its pretty much identical to the previous version... the only difference is that we're using our new 'before advice' (encapsulated as an instance of the ConsoleLoggingBeforeAdvice class).

    ProxyFactory factory = new ProxyFactory(new ServiceCommand());
    factory.AddAdvice(new ConsoleLoggingBeforeAdvice());
    ICommand command = (ICommand) factory.GetProxy();
    command.Execute();

The result of executing the above snippet of code will look something like this...

    Intercepted call to this method : Execute
    The target is                   : Spring.Examples.AopQuickStart.ServiceCommand
    The arguments are               :

The output clearly indicates that the advice was applied before the invocation of the advised method. Notice that in contrast to 'around advice', with 'before advice' there is no chance of forgetting to call the Proceed() method on the target, because one does not have access to the IMethodInvocation (as is the case with 'around advice')... similarly, you cannot forget to return the return value either.

If you can use 'before advice', then do so. The simpler programming model offered by 'before advice' means that there is less to remember, and thus potentially less things to get wrong.

Here is the Spring.NET XML configuration for applying our 'before advice' declaratively...

    <object id="beforeAdvice"
	    type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"/>

    <object id="myServiceObject"
        type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="target">
            <object id="myServiceObjectTarget"
                type="Spring.Examples.AopQuickStart.ServiceCommand"/>
        </property>
        <property name="interceptorNames">
            <list>
                <value>beforeAdvice</value>
            </list>
        </property>
    </object>

17.3.1.2. After advice

Just as 'before advice' defines advice that executes before an advised target, 'after advice' is advice that executes after a target has been executed.

'after advice' in Spring.NET is defined by the IAfterReturningAdvice interface in the Spring.Aop namespace. Again, lets just fire on ahead with an example... again, we'll use the same scenario as before to keep things simple.

    public class ConsoleLoggingAfterAdvice : IAfterReturningAdvice
    {
        public void AfterReturning(
            object returnValue, MethodInfo method, object[] args, object target)
        {
            Console.Out.WriteLine("This method call returned successfully : " + method.Name);
            Console.Out.WriteLine("    The target was                     : " + target);
            Console.Out.WriteLine("    The arguments were                 : ");
            if(args != null)
            {
                foreach (object arg in args)
                {
                    Console.Out.WriteLine("\t: " + arg);
                }
            }
            Console.Out.WriteLine("    The return value is                : " + returnValue);
        }
    }

Let's apply a single instance of the ConsoleLoggingAfterAdvice advice to the invocation of the Execute() method of the ServiceCommand. What follows is programmatic configuration; as you can, its pretty much identical to the 'before advice' version (which in turn was pretty much identical to the original 'around advice' version)... the only real difference is that we're using our new 'after advice' (encapsulated as an instance of the ConsoleLoggingAfterAdvice class).

    ProxyFactory factory = new ProxyFactory(new ServiceCommand());
    factory.AddAdvice(new ConsoleLoggingAfterAdvice());
    ICommand command = (ICommand) factory.GetProxy();
    command.Execute();

The result of executing the above snippet of code will look something like this...

    This method call returned successfully : Execute
    The target was                         : Spring.Examples.AopQuickStart.ServiceCommand
    The arguments were                     :
    The return value is                    : null

The output clearly indicates that the advice was applied after the invocation of the advised method. Again, it bears repeating that your real world development will actually have an advice implementation that does something useful after the invocation of an advised method. Notice that in contrast to 'around advice', with 'after advice' there is no chance of forgetting to call the Proceed() method on the target, because just like 'before advice' you don't have access to the IMethodInvocation... similarly, although you get access to the return value of the target, you cannot forget to return the return value either. You can however change the state of the return value, typically by setting some of its properties, or by calling methods on it.

The best-practice rule for 'after advice' is much the same as it is for 'before advice'; namely that if you can use 'after advice', then do so (in preference to using 'around advice'). The simpler programming model offered by 'after advice' means that there is less to remember, and thus less things to get potentially wrong.

A possible use case for 'after advice' would include performing access control checks on the return value of an advised method invocation; consider the case of a service that returns a list of document URI's... depending on the identity of the (Windows) user that is running the program that is calling this service, one could strip out those URI's that contain sensitive data for which the user does not have sufficient priviliges to access. That is just one (real world) scenario... I'm sure you can think of plenty more that are a whole lot more relevant to your own development needs.

Here is the Spring.NET XML configuration for applying the 'after advice' declaratively...

    <object id="afterAdvice"
	    type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"/>

    <object id="myServiceObject"
        type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="target">
            <object id="myServiceObjectTarget"
                type="Spring.Examples.AopQuickStart.ServiceCommand"/>
        </property>
        <property name="interceptorNames">
            <list>
                <value>afterAdvice</value>
            </list>
        </property>
    </object>

17.3.1.3. Throws advice

So far we've covered 'around advice', 'before advice', and 'after advice'... these advice types will see you through most if not all of your AOP needs. However, one of the remaining advice types that Spring.NET has in its locker is 'throws advice'.

'throws advice' is advice that executes when an advised method invocation throws an exception.. hence the name. One basically applies the 'throws advice' to a target object in much the same way as any of the previously mentioned advice types. If during the execution of ones application none of any of the advised methods throws an exception, then the 'throws advice' will never execute. However, if during the execution of your application an advised method does throw an exception, then the 'throws advice' will kick in and be executed. You can use 'throws advice' to apply a common exception handling policy across the varoius objects in your application, or to perform logging of every exception thown by an advised method, or to alert (perhaps via email) the support team in the case of particularly of critical exceptions... the list of possible uses cases is of course endless.

The 'throws advice' type in Spring.NET is defined by the IThrowsAdvice interface in the Spring.Aop namespace... basically, one defines on one's 'throws advice' implementation class what types of exception are going to be handled. Lets take a quick look at the IThrowsAdvice interface...

    public interface IThrowsAdvice : IAdvice
    {
    }

Yes, that is really it... it is a marker interface that has no methods on it. You may be wondering how Spring.NET determines which methods to call to effect the running of one's 'throws advice'. An example would perhaps be illustrative at this point, so here is some simple Spring.NET style 'throws advice'...

    public class ConsoleLoggingThrowsAdvice : IThrowsAdvice
    {
        public void AfterThrowing(Exception ex)
        {
            Console.Out.WriteLine("Advised method threw this exception : " + ex);
        }
    }

Lets also change the implementation of the Execute() method of the ServiceCommand class such that it throws an exception. This will allow the advice encapsulated by the above ConsoleLoggingThrowsAdvice to kick in.

    public class ServiceCommand : ICommand
    {
        public void Execute()
        {
            throw new UnauthorizedAccessException();
        }
    }

Let's programmatically apply the 'throws advice' (an instance of our ConsoleLoggingThrowsAdvice) to the invocation of the Execute() method of the above ServiceCommand class; to wit...

    ProxyFactory factory = new ProxyFactory(new ServiceCommand());
    factory.AddAdvice(new ConsoleLoggingThrowsAdvice());
    ICommand command = (ICommand) factory.GetProxy();
    command.Execute();

The result of executing the above snippet of code will look something like this...

    Advised method threw this exception : System.UnauthorizedAccessException:
    Attempted to perform an unauthorized operation.

As can be seen from the output, the ConsoleLoggingThrowsAdvice kicked in when the advised method invocation threw an exception. There are a number of things to note about the ConsoleLoggingThrowsAdvice advice class, so lets take them each in turn.

In Spring.NET, 'throws advice' means that you have to define a class that implements the IThrowsAdvice interface. Then, for each type of exception that your 'throws advice' is going to handle, you have to define a method with this signature...

    void AfterThrowing(Exception ex)

Basically, your exception handling method has to be named AfterThrowing. This name is important... your exception handling method (s) absolutely must be called AfterThrowing. If your handler method is not called AfterThrowing, then your 'throws advice' will never be called, it's as simple as that. Currently, this naming restriction is not configurable (although it may well be opened up for configuration in the future).

Your exception handling method must (at the very least) declare a parameter that is an Exception type... this parameter can be the root Exception class (as in the case of the above example), or it can be an Exception subclass if you only want to handle certain types of exception. It is good practice to always make your exception handling methods have an Exception parameter that is the most specialized Exception type possible... i.e. if you are applying 'throws advice' to a method that could only ever throw ArgumentExceptions, then declare the parameter of your exception handling method as...

    void AfterThrowing(ArgumentException ex)

Note that your exception handling method can have any return type, but returning any value from a Spring.NET 'throws advice' method would be a waste of time... the Spring.NET AOP infrastructure will simply ignore the return value, so always define the return type of your exception handling methods to be void.

Finally, here is the Spring.NET XML configuration for applying the 'throws advice' declaratively...

    <object id="throwsAdvice"
	    type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"/>

    <object id="myServiceObject"
        type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="target">
            <object id="myServiceObjectTarget"
                type="Spring.Examples.AopQuickStart.ServiceCommand"/>
        </property>
        <property name="interceptorNames">
            <list>
                <value>throwsAdvice</value>
            </list>
        </property>
    </object>

One thing that cannot be done using 'throws advice' is exception swallowing. It is not possible to define an exception handling method in a 'throws advice' implementation that will swallow any exception and prevent said exception from bubbling up the call stack. The nearest thing that one can do is define an exception handling method in a 'throws advice' implementation that will wrap the handled exception in another exception; one would then throw the wrapped exception in the body of one's execption handling method. One can use this to implement some sort of exception translation or exception scrubbing policy, in which implementation specific exceptions (such as SqlException or OracleException exceptions being thrown by an advised data access object) get replaced with a business exception that has meaning to the service objects in one's business layer. A toy example of this type of 'throws advice' can be seen below.

    public class DataAccessExceptionScrubbingThrowsAdvice : IThrowsAdvice
    {
        public void AfterThrowing (SqlException ex)
        {
            // business objects in higher level service layer need only deal with PersistenceException...
            throw new PersistenceException ("Cannot access persistent storage.", ex.StackTrace);
        }
    }

Spring.NET's data access library already has this kind of functionality (and is a whole lot more sophisticated)... the above example is merely being used for illustrative purposes.

This treatment of 'throws advice', and of Spring.NET's implementation of it is rather simplistic. 'throws advice' features that have been omitted include the fact that one can define exception handling methods that permit access to the original object, method, and method arguments of the advised method invocation that threw the original exception. This is a quickstart guide though, and is not meant to be exhaustive... do consult the 'throws advice' section of the reference documentation, which describes how to declare an exception handling method that gives one access to the above extra objects, and how to declare multiple exception handling methods on the same IThrowsAdvice implementation class (see Section 9.3.2.3, “Throws advice”).

17.3.1.4. Introductions (mixins)

In a nutshell, introductions are all about adding new state and behaviour to arbitrary objects... transparently and at runtime. Introductions (also called mixins) allow one to emulate multiple inheritance, typically with an eye towards applying crosscutting state and operations to a wide swathe of objects in your application that don't share the same inheritance hierarchy.

17.3.1.5. Layering advice

The examples shown so far have all demonstrated the application of a single advice instance to an advised object. Spring.NET's flavor of AOP would be pretty poor if one could only apply a single advice instance per advised object... it is perfectly valid to apply multiple advice to an advised object. For example, one might apply transactional advice to a service object, and also apply a security access checking advice to that same advised service object.

In the interests of keeping this section lean and tight, let's simply apply all of the advice types that have been previously described to a single advised object... in this first instance we'll just use the default pointcut which means that every possible joinpoint will be advised, and you'll be able to see that the various advice instances are applied in order.

Please do consult the class definitions for the following previously defined advice types to see exactly what each advice type implementation does... we're going to be using single instances of the ConsoleLoggingAroundAdvice, ConsoleLoggingBeforeAdvice, ConsoleLoggingAfterAdvice, and ConsoleLoggingThrowsAdvice advice to advise a single instance of the ServiceCommand class.

    ProxyFactory factory = new ProxyFactory(new ServiceCommand());
    factory.AddAdvice(new ConsoleLoggingBeforeAdvice());
    factory.AddAdvice(new ConsoleLoggingAfterAdvice());
    factory.AddAdvice(new ConsoleLoggingThrowsAdvice());
    factory.AddAdvice(new ConsoleLoggingAroundAdvice());
    ICommand command = (ICommand) factory.GetProxy();
    command.Execute();

Here is the Spring.NET XML configuration for declaratively applying multiple advice.

    <object id="throwsAdvice"
	    type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"/>
    <object id="afterAdvice"
	    type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"/>
    <object id="beforeAdvice"
	    type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"/>
    <object id="aroundAdvice"
	    type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"/>

    <object id="myServiceObject"
        type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="target">
            <object id="myServiceObjectTarget"
                type="Spring.Examples.AopQuickStart.ServiceCommand"/>
        </property>
        <property name="interceptorNames">
            <list>
                <value>throwsAdvice</value>
                <value>afterAdvice</value>
                <value>beforeAdvice</value>
                <value>aroundAdvice</value>
            </list>
        </property>
    </object>

17.3.1.6. Configuring advice

In case it is not immediately apparent, remember that advice is just a plain old .NET object (a PONO); advice can have constructors that can take any number of parameters, and like any other .NET class, advice can have properties. What this means is that one can leverage the power of the Spring.NET IoC container to apply the IoC principle to one's advice, and in so doing reap all the benefits of Dependency Injection.

Consider the case of throws advice that needs to report (fatal) exceptions to a first line support centre. The throws advice could declare a dependency on a reporting service via a .NET property, and the Spring.NET container could dependency inject the reporting service dependency into the throws advice when it is being created; the reporting dependency might be a simple Log4NET wrapper, or a Windows EventLog wrapper, or a custom reporting exception reporting service that sends detailed emails concerning the fatal exception.

Also bear in mind the fact that Spring.NET's AOP implementation is quite independent of Spring.NET's IoC container. As you have seen, the various examples used in this have illustrated both programmatic and declarative AOP configuration (the latter being illustrated via Spring.NET's IoC XML configuration mechanism).

17.3.2. Using Attributes to define Pointcuts

17.4. The Spring.NET AOP Cookbook

The preceding treatment of Spring.NET AOP has (quite intentionally) been decidedly simple. The overarching aim was to convey the concepts of Spring.NET AOP... this section of the Spring.NET AOP guide contains a number of real world examples of the application of Spring.NET AOP.

17.4.1. Caching

This example illustrates one of the more common usages of AOP... caching.

Lets consider the scenario where we have some static reference data that needs to be kept around for the duration of an application. The data will almost never change over the uptime of an application, and it exists only in the database to satisfy referential integrity amongst the various relations in the database schema. An example of such static (and typically immutable) reference data would be a collection of Country objects (comprising a country name and a code). What we would like to do is suck in the collection of Country objects and then pin them in a cache. This saves us having to hit the back end database again and again every time we need to reference a country in our application (for example, to populate dropdown controls in a Windows Forms desktop application).

The Data Access Object (DAO) that will load the collection of Country objects is called AdoCountryDao (it is an implementation of the data-access-technology agnostic DAO interface called ICountryDao). The implementation of the AdoCountryDao is quite simple, in that every time the FindAllCountries instance method is called, an instance will query the database for an IDataReader and hydrate zero or more Country objects using the returned data.

    public class AdoCountryDao : ICountryDao
    {
        public IList FindAllCountries ()
        {
            // implementation elided for clarity...
            return countries;
        }
    }

Ideally, what we would like to have happen is for the results of the first call to the FindAllCountries instance method to be cached. We would also like to do this in a non-invasive way, because caching is something that we might want to apply at any number of points across the codebase of our application. So, to address what we have identified as a cross cutting concern, we can use Spring.NET AOP to implement the caching.

The mechanism that this example is going to use to identify (or pick out) areas in our application that we would like to apply caching to is a .NET Attribute. Spring.NET ships with a number of useful custom .NET Attribute implementations, one of which is the cunningly named CacheAttribute. In the specific case of this example, we are simply going to decorate the definition of the FindAllCountries instance method with the CacheAttribute.

    public class AdoCountryDao : ICountryDao
    {
        [Cache]
        public IList FindAllCountries ()
        {
            // implementation elided for clarity...
            return countries;
        }
    }

The SpringAir reference application that is packaged as part of the Spring.NET distribution comes with a working example of caching applied using Spring.NET AOP (see Chapter 19, SpringAir - Reference Application).

17.4.2. Performance Monitoring

This recipe show how easy it is to instrument the classes and objects in an application for performance monitoring. The performance monitoring implementation uses one of the (many) Windows performance counters to display and track the performance data.

17.4.3. Retry Rules

This final recipe describes a simple (but really quite useful) aspect... retry logic. Using Spring.NET AOP, it is quite easy to surround an operation such as a method that opens a connection to a database with a (configurable) aspect that tries to obtain a database connection any number of times in the event of a failure.

17.5. Spring.NET AOP Best Practices

Spring.NET AOP is an 80% AOP solution, in that it only tries to solve the 80% of those cases where AOP is a good fit in a typical enterprise application. This final section of the Spring.NET AOP guide describes where Spring.NET AOP is typically useful (the 80%), as well as where Spring.NET AOP is not a good fit (the 20%).