AOP with Castle Windsor
Asked Answered
T

0

6

What I'm trying to achieve is AOP via attributes using Castle Windsor interceptors. I've had some success but having trouble with the aspects at the class level vs. the method level.

  • If I use class level attributes only, all methods will be intercepted.
  • If I use method level attributes only, those methods will be intercepted.
  • If I add a class level attribute, and a method level attribute, both interceptions will happen on methods that were attributed, but the ones that were not will not be intercepted.

So given this component:

public interface IMyComponent
{
    void ShouldBeInterceptedByStopWatch_AND_ExceptionLogger();
    void ShouldBeInterceptedByExceptionLogger();
}

[LogExceptionAspect]
public class MyComponent : IMyComponent
{
    [StopwatchAspect]
    public void ShouldBeInterceptedByStopWatch_AND_ExceptionLogger()
    {
        for (var i = 0; i < 2; i++) Thread.Sleep(1000);
    }

    public void ShouldBeInterceptedByExceptionLogger()
    {
        throw new NotImplementedException();
    }
}

I would expect the logger aspect to intercept ShouldBeInterceptedByExceptionLogger() but its not happening unless I remove the stopwatch aspect from the other method, or remove the logger aspect from the class and add it to the ShouldBeInterceptedByExceptionLogger(). BUT the ShouldBeInterceptedByStopWatch_AND_ExceptionLogger() is intercepted by both.

The entire sample application can be found at - https://bitbucket.org/jayala/juggernet-aop

basically what its doing is using a facility to register a IContributeComponentModelConstruction that will add an interceptor if it finds an aspect at class level, or add an interceptor + method hooks if it finds aspects at method level.

This is how I bootstrap the container:

        var container = new WindsorContainer()
            .AddFacility<LogExceptionAspectFacility>()
            .AddFacility<StopwatchAspectFacility>()
            .Register(Component
                .For<IMyComponent>()
                .ImplementedBy<MyComponent>()
                .LifeStyle.Transient);

What the facilities are doing is registering an interceptor and a model contributor like this

public abstract class BaseAspectFacility<TAspectAttribute, TAspectInterceptor> : AbstractFacility
    where TAspectAttribute : Attribute
    where TAspectInterceptor : IInterceptor
{
    protected override void Init()
    {
        var interceptorName = Guid.NewGuid().ToString();
        Kernel.Register(Component.For<IInterceptor>()
                                 .Named(interceptorName)
                                 .ImplementedBy<TAspectInterceptor>()
                                 .LifeStyle.Singleton);
        var contributor = new ContributeAspectToModel<TAspectAttribute>(interceptorName);
        Kernel.ComponentModelBuilder.AddContributor(contributor);
    }
}
Toole answered 27/7, 2012 at 15:9 Comment(5)
Old post but if you post your interceptor implementation I'll take a look.Chere
I haven't revisited this in a long time and there would be a lot to post. Did you check out the BitBucket repo? There isn't much to the interceptors. I think the problem is the way I associate the interceptors to the object getting injected. Check out Program.cs to see how I bootstrap the container.Toole
As a general rule I would suggest implementing IModelInterceptorSelector on your pointcuts if you want to intercept all methods on a class. If you want to be specific about which methods to intercept I would implement IInterceptorSelector instead. That interface exposes a SelectInterceptor method that exposes a Type, a MethodInfo and an array of IInterceptors that you can use to define your selection criteria at the method level. Posting as a comment because I didn't really answer your question.Chere
I would go back and ask myself if I am doing to much in a single class if I need this much flexibility in outfitting my methods / classes with what could potentially be complex interceptor selector criteria. Imagine half a dozen or a dozen aspects scattered around a class with as many methods. It may be hard to tell what is going on. Instead, I would suggest that you try to focus your classes on a single responsibility and compose them in a way that allows you to get your desired result by attributing them at the class level only.Chere
Or (better yet) drop the attributes and intercept conventional interfaces that your concrete classes implement. Then compose them together in a way that produces the desired behavior.Chere

© 2022 - 2024 — McMap. All rights reserved.