Home

Castle Stronghold

Tutorial

So you think your project might benefit from some AOP approach. This tutorial introduces the Aspect# approach for AOP. Basically we are going to talk about the Aspect# built-in language for declaring aspects, mixins and interceptors.

The final sourcecode for this tutorial is included in the Aspect# distribution under the AspectSharpExample directory. It can be browsed in SVN here: http://svn.castleproject.org/svn/castle/trunk/AspectSharp/AspectSharp.Example/

The application starts in: AspectSharpExample/Application.cs

An hypothetical situation - not so much

To make things more interesting, lets suppose you're working on a specific application. You're creating a revolutionary Content Management System, and you probably end up with a big although nice and simple object model. The most important components implement IContentProvider and IView. IContentProvider is obviously responsible for gathering content from some source like database, Xml, RSS, Excel files and IView is responsible for displaying it in a specific way for a specific channel.

Everything is fine and your almost done with your four thousand ContentProviders and Views that cover all existing communications channels available in the world today. Suddenly, the sales guy - always blame the sales guy - comes, with from his standpoint, an non-important requirement. He needs security checking for providers and views, and he already sold it as done for an important customer, lets say the BBC. Your company's future depends on having it completed by the end of the day!

The available solutions

You need to expose your objects as a securable resource for your security framework. To ease the burden of having to change every single ContentProvider and View you think about a few possibilities:

The problem with these possibilities is that they all will bungle your nice and clean object model. In your conception security doesn't have anything to do with content providers and views, but for some of them it makes sense. So, for those that make sense you'd like to introduce the ISecurityResource interface and implementation.

Well, c'mon! You only have a few hours, start to modify those components now! Not so fast, let's use AOP for it.

The Mixin solution

Nowadays, many AOP frameworks implement the mixin functionality. Though it's not really an AOP concept, while this is introducing something to a class of a set of classes, then it's all right, we can call it AOP.

The idea here is to make all ContentProvider in a given namespace implement the ISecurityResource interface with a valid implementation, of course. We can do this like this:


 public class SecurityResourceImpl : ISecurityResource
 {
       public SecurityResourceImpl()
       {
       }
 
       public String ResourceName
       {
             get { return "Content"; }
       } 
 }

Now we need to apply this to a particular class or to a set of classes in our project.

Describing your aspect configuration

We use a built-in language (Ruby like) to configure the aspects. You can keep this configuration in a external file, in your code (not recommended) or in the .config file associated with your application.

 import YourCompany.CMS.ContentProviders in YourCompanyAssembly
 
 aspect SecurityAspect for RSSContentProvider
 
     include Mixins.SecurityResourceImpl in MyMixinsAssembly
 
 end

This aspect targets the RSSContentProvider class and includes the SecurityResourceImpl class. What does it mean? Well, when you get your RSSContentProvider instance it will have the ISecurityResource interface implemented by the SecurityResourceImpl.

You mixed them, hence Mixin :-)

Instead of targeting a specific class, you can targets a set of classes like all the classes in the given namespace:

 import YourCompany.CMS.ContentProviders in YourCompanyAssembly
 
 aspect SecurityAspect for [ YourCompany.CMS.ContentProviders ]
 
   include Mixins.SecurityResourceImpl in MyMixinsAssembly
 
 end

Now we need to create an Aspect# engine to do this magic:


 StreamReader reader = new StreamReader( configfile );
 AspectEngineBuilder builder = new AspectLanguageEngineBuilder(reader);
 
 AspectEngine engine = builder.Build();
 RSSContentProvider provider = engine.Wrap( new RSSContentProvider() );
But wait a minute! This is a very naive implementation of ISecurityResource. What if the security resource needs to access something from the content provider or the view? Gotcha

Not really. If your mixin needs to access the underlying component it must implement the IProxyAware interface:


 public class SecurityResourceImpl : ISecurityResource, IProxyAware
 {
        private String _name;
 
        public SecurityResourceImpl()  
        {  
        }
 
        public void SetProxy(object proxy)  
        {  
                if (proxy is IContentProvider)  
                {  
                        Name = (proxy as IContentProvider).Name;  
                }  
                else if (proxy is IView)  
                {  
                        Name = (proxy as IView).Name;  
                }  
        }
 
        public String Name  
        {  
                get { return _name; }  
                set { _name = value; }  
        }
 
        public String ResourceName  
        {  
                get { return Name; }  
        }  
  }

Your mixin doesn't need to implement or expose anything, but if it does implement some interface then the Wrap'ed instance will expose them and forward the calls. Your mixin must have a default constructor, though.

Intercepting invocations

The most sensible method in IContentProvider is the RetrieveContent method, so for every content provider, which implements the ISecurityResource interface, it is a good idea to invoke the ISecurityResource.Demand() to fire all security checks.

Time to change the content provider code... well wait! Maybe Aspect# can help us implementing this check for us.

You're right! All we need to do is intercept the methods we want and perform the check. First we need a pointcut which will select the methods or properties. Within a pointcut you can add advices that will perform some action on the resulting Joinpoints.

What a lot of new words! Ok, so lets get things clear:

Aspect# supports only one type of advice: MethodInterceptor. MethodInterceptors allow you to execute some code before and|or after a target method. Lets do it:

 import YourCompany.CMS.ContentProviders in YourCompanyAssembly
 import YourCompany.CMS.Aop.Interceptors
 
 aspect SecurityAspect for RSSContentProvider
      include Mixins.SecurityResourceImpl in MyMixinsAssembly
 
      pointcut method(* RetrieveContent(*))
            advice(SecurityCheckInterceptor)
      end
 end

Our pointcut states 'I don't care about the return value, just match all methods named RetrieveContent and I don't care about its arguments either'. So we don't have to worry about other methods being checked unnecessarily.

And now for something completely different: our MethodInterceptor implementation:


 public class SecurityCheckInterceptor : IMethodInterceptor
 {
    public object Invoke(IMethodInvocation invocation)
    {
        ISecurityResource target = invocation.GetThis() as ISecurityResource;
        target.Demand(); // Can throw a SecurityException
 
        return invocation.Proceed(); // All right, get on with it
    }
 }

This implementation is pretty straightforward. Please note that the GetThis returns the proxy, so if you, for instance, invoke RetrieveContent within the interceptor then your interceptor will be called again and you can end up with a stack overflow.

Conclusion

Its easy to solve several common problems in an application with AOP. Aspect#

tries to ease the burden of using AOP and do it propertly. Now our two minute tutorial is over. If you're complaining that you spent more than two minutes reading this, well.. I'm a slow reader myself :-)

Where to go from here?

Google
Search WWW Search castleproject.org