Castle Windsor AOP - Dependency Injection and Aspect-Oriented Programming - Policy Injection Application Block

Castle Windsor AOP - Dependency Injection and Aspect-Oriented Programming - Policy Injection Application Block

by David Hayden ( Sarasota Web Design ), Filed: Enterprise Library 3.0

 

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.

Get the source code on the downloads page.

Source: David Hayden ( Sarasota Web Design ), Filed: Enterprise Library 3.0

 

posted on Wednesday, March 14, 2007 9:34 AM

My Links

Post Categories

Article Categories

Archives

Loose-Leaf Tea