Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Windsor AOP – Policy Injection Application Block – Best Way to Use Windsor AOP?

Ayende introduced me to a part of Windsor that I never knew existed – the ability to do both Dependency Injection and AOP! The combination is very, very exciting and has been on my mind ever since the release of the Enterprise Library 3.0 Policy Injection Application Block which doesn't appear to offer the sweet combination of features!

I took Ayende's example apart, which is a great example of using Facilities, too, and made a similar version just for kicks as I was learning about Interceptors, Facilities, and AOP all at the same time. I am amazed by the flexibility and still have yet to grok the potential here. I can't wait to put MonoRail into the picture and see where all this goes.

Using my previous example of the Policy Injection Application Block, I provided similar functionality using Windsor and used the Logging Application Block from Enterprise Library 3.0 to do the logging.

I made my version a little more simplistic than Ayende's by introducting a facility that worked with Tags. Each Tag just maps to an Interceptor:

 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <facilities>
        <facility id="TagFacility" type="WindsorAOP.TagFacility, WindsorAOP">
            <tags>
                <tag name="Log" type="WindsorAOP.LogInterceptor, WindsorAOP" />
                <tag name="Another" type="WindsorAOP.AnotherInterceptor, WindsorAOP" />
            </tags>
        </facility>
    </facilities>
    <components>
        <component id="Order" service="WindsorAOP.IOrder, WindsorAOP" type="WindsorAOP.Order, WindsorAOP" lifestyle="transient" />
    </components>
</configuration>

 

The Tag Facility, not totally refactored, just reads registered tags from the configuration and searches for these Tags using custom attributes on components as they are being registered. If found, interceptors are attached appropriately:

 

public class TagFacility : AbstractFacility
{
    Dictionary<string,Type> _registeredTags = new Dictionary<string,Type>();

    protected override void Init()
    {
        SetupConfiguration();
        Kernel.ComponentRegistered += new ComponentDataDelegate(Kernel_ComponentRegistered);
    }

    private void SetupConfiguration()
    {
        IConfiguration tagSection = FacilityConfig.Children["tags"];

        if (tagSection != null)
        {
            foreach (IConfiguration tags in tagSection.Children)
            {
                _registeredTags.Add(tags.Attributes["name"], Type.GetType(tags.Attributes["type"]));
                Kernel.AddComponent(tags.Attributes["name"], Type.GetType(tags.Attributes["type"]));
            }
        }
    }

    void Kernel_ComponentRegistered(string key, IHandler handler)
    {
        string[] tags = GetTags(handler.ComponentModel.Service);

        foreach (string tag in tags)
        {
            if (_registeredTags.ContainsKey(tag))
                handler.ComponentModel.Interceptors.Add(new InterceptorReference(_registeredTags[tag]));
        }
    }

    string[] GetTags(Type service)
    {
        List<string> tags = new List<string>();

        MethodInfo[] methods = service.GetMethods();

        foreach (MethodInfo info in methods)
        {
            TagAttribute[] attributes = (TagAttribute[])info.GetCustomAttributes(typeof (TagAttribute), true);
            foreach (TagAttribute attribute in attributes)
                tags.Add(attribute.Name);
        }

        return tags.ToArray();
    }
}

 

I can't tell you how much I love the potential here. Really opens my eyes as to how cool Windsor is.

 

Now I have this cool ability to add Tags that Map to Interceptors and attach them via TagAttributes on dependency injected components:

 

public interface IOrder
{
    [Tag("Another")] // Second to Run
    [Tag("Log")] // First to Run
    string Return(string reason);
}

 

When the LogInterceptor gets called it just logs something via the Logging Application Block in EntLib 3.0:

 

public class LogInterceptor : IInterceptor
{
    #region IInterceptor Members

    public void Intercept(IInvocation invocation)
    {
        // PreCall
        StringBuilder sb = new StringBuilder();

        sb.AppendFormat("{0} Method Called.\n", invocation.Method.Name);

        for (int i = 0; i < invocation.Arguments.Length; i++)
        {
            sb.AppendFormat("  Argument {0}: {1} - {2}\n", (i + 1).ToString(), invocation.Method.GetParameters()[i].Name, invocation.Arguments[i].ToString());
        }

        Logger.Write(sb.ToString());

        // Proceed
        invocation.Proceed();

        // PostCall
        // Could do somthing...
    }

    #endregion
}

 

I saw a StandardInterceptor that could clean this up a bit as there are PreCalls and PostCalls and apparently ways to specify the halting / continuation of the execution of the chain of Interceptors. I unfortunately ran out-of-time to dive into those bits and look forward to spending more time on Windsor this week.

 

One thing that Ayende mentions in his blog post, however, is that there are better ways to use AOP in Windsor. I am wondering what they are? The documentation seems a little thin on this subject and I really want to dig into it more and understand alternative ways to using AOP with Windsor as well as best practices.

 

I would love to hear how developers are using the functionality as well as find more examples online and/or that can be dowloaded. How are you using Windsor AOP or AOP in general?

I will post my source code for kicks as soon as I clean it up a bit :) I wanted to get this post out today so I could learn how others are using it and more about best practices.

by David Hayden

 

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

4 Responses to Windsor AOP – Policy Injection Application Block – Best Way to Use Windsor AOP?

  1. dhayden says:

    Claudio,

    Thanks for the reminder. You can download the source code for my downloads page:

    http://davidhayden.com/davidhayden/downloads.aspx

  2. We wait for the source code.
    Thk.

  3. Castle also sports an Aspect# facility that allows you to advice components using a Ruby-esque language for point-cutting. You can read more about the Aspect# integration facility here http://castleproject.org/container/facilities/v1rc3/asharptintegration/index.html
    I recently wrote a blog post (shameless plug) on how to use Windsor / Aspect# to profile applications; http://andersnoras.com/blogs/anoras/archive/2007/02/18/quot-in-flight-quot-profiling-with-aop.aspx
    This post shows a more advanced logging scenario.

  4. This is the recommended approach for using AOP on Windsor.
    What I meant that I wouldn’t build something like the Policy Application Block, simply because it doesn’t really gives me anything special.

    Specifically, the use cases for simple interception AOP are quite limited. Mostly logging and that is about it.
    If you want to do some of the really interesting stuff, you are going to want to know more, configuration, knowing what are you intercepting, etc.
    This leads to trying to pass more data than is easy via the XML.
    I does AOP by building facility + interceptor + inspector / contributer on a case by case basis.
    It is not a lot of code (and certainly not repeated one) and it gives me a lot of flexibility without having to put extensability hooks all over the place

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>