3
votes

I'm using Castle Windsor 3.0.

I have a component that should be started automatically after the registration phase. I would also like to intercept exceptions coming from it's Start/Stop methods and log their details.

To make my component startable, I used the Startable facility that comes with Windsor:

container.AddFacility<StartableFacility>(f => f.DeferredStart());

I created a custom interceptor like this:

class ExceptionLoggerInterceptor : IInterceptor
{
    IExceptionLogger m_ExceptionLogger;

    public ExceptionLoggerInterceptor(IExceptionLogger exceptionLogger)
    {
        if (exceptionLogger == null)
            throw new ArgumentNullException("exceptionLogger");

        m_ExceptionLogger = exceptionLogger;
    }

    public void Intercept(IInvocation invocation)
    {
        try
        {
            invocation.Proceed();
        }
        catch (Exception ex)
        {
            m_ExceptionLogger.Write(ex, invocation.Method.Name, invocation.TargetType.Name);
        }
    }
}

and I registered the component like this:

Component.For<IExceptionLogger>()
 .ImplementedBy<EnterpriseLibraryExceptionLogger>()
 .LifeStyle.Singleton,

Component.For<ExceptionLoggerInterceptor>()
 .LifeStyle.Singleton,

Component.For<IWorkflowService>()
 .ImplementedBy<WorkflowService>()
 .LifeStyle.Singleton
 .StartUsingMethod(c => c.Start)
 .StopUsingMethod(c => c.Stop)
 .Interceptors(InterceptorReference.ForType<ExceptionLoggerInterceptor>()).Anywhere

To make a test, I coded a dirty

throw new Exception(); 

in the implementation of the Start method of the component. At registration phase, when Windsor automatically calls the Start method on the component, the exception is thrown, but never intercepted by my custom interceptor.

I made another test, this time without using the Startable facility but rather calling the Start method manually. The exception got thrown and was intercepted by my custom interceptor.

So, as the title of this post asks, is there a way to intercept methods called by the Startable facility with Windsor?

Regards

Louis-Pierre Beaumont

1

1 Answers

2
votes

I'm going to partially answer my own question:

I did not find any way to intercept the Start method on a component when using the Startable facility. It looks like the facility is not using the proxy created for the object to perform the call, but the object itself.

A dedicated post presents the problem here.

Anyway, I quicly figured out that doing AOP with Proxy objects has it's limits. That's why I moved to SheepAspect, an IL Weaving AOP Framework.

I mixed SheepAspect with Castle Windsor, and now, when my component's Start method is called by the Castle Startable facility, all my aspects are also called!

Here is how i wrote my ExceptionAspect with SheepAspect:

[SingletonAspect]
public class ExceptionAspect
{
    IExceptionLogger m_ExceptionLogger;

    public ExceptionAspect(IExceptionLogger exceptionLogger)
    {
        if (exceptionLogger == null)
            throw new ArgumentNullException("exceptionLogger");

        m_ExceptionLogger = exceptionLogger;
    }

    [SelectTypes(typeof(WorkflowService))]
    void Targets() { }

    [Around("Execute")]
    [SelectMethods("Name:('Start') & InType:@Targets")]
    public void Execute(MethodJointPoint jp)
    {
        object result = null;

        try
        {
            result = jp.Execute();
        }
        catch (Exception ex)
        {
            m_ExceptionLogger.Write(ex, jp.Method.Name, jp.Method.ReflectedType.Name);
        }

        return result;
    }
}