Question

I have a WindsorContainer with a IModelInterceptorsSelector. It works well except for component's that have no implementation (eg. have all behavior handled dynamically by an IInterceptor).

If I try to resolve a component with an interface only, I get:

Castle.MicroKernel.ComponentActivator.ComponentActivatorException occurred
  Message=Could not find a public constructor for type ConsoleApplication1.IInterfaceOnlyService. Windsor can not instantiate types that don't expose public constructors. To expose the type as a service add public constructor, or use custom component activator.
  Source=Castle.Windsor
  StackTrace:
       at Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.FastCreateInstance(Type implType, Object[] arguments, Type[] signature)

But if I manually specify the interceptor at registration time, it works just fine. Is this a bug in Windsor or am I doing something wrong?

The code to reproduce is fairly straightforward:

        var container = new WindsorContainer();
        container.Kernel.ProxyFactory.AddInterceptorSelector(new Selector());
        container.Register(Component.For<TestInterceptor>());
        container.Register(Component.For<IInterfaceOnlyService>()); // this doesn't work
        // container.Register(Component.For<IInterfaceOnlyService>().Interceptors<TestInterceptor>());  // this works
        var i = container.Resolve<IInterfaceOnlyService>();


    public class Selector : IModelInterceptorsSelector
    {
        public bool HasInterceptors(ComponentModel model)
        {
            return model.Service != typeof (TestInterceptor);
        }

        public InterceptorReference[] SelectInterceptors(ComponentModel model, InterceptorReference[] interceptors)
        {                
            return new[] { InterceptorReference.ForType<TestInterceptor>() };
        }
    }

Thanks.

Was it helpful?

Solution

This definitely seems to be a bug in Windsor. It looks like it has to do with accepting an InterceptorGroup for components without a target. That is:

container.Register(Component.For<IInterfaceOnlyService>  
().Interceptors<TestInterceptor>());

works.

container.Register(Component.For<IInterfaceOnlyService>  
().Interceptors(InterceptorReference.ForType(typeof(TestInterceptor))));

In looking at the Castle source, the difference is that the first adds adescriptor directly:

return this.AddDescriptor(new InterceptorDescriptor<TService>(new  
InterceptorReference[] { new InterceptorReference(typeof(TInterceptor)) }));

But the second uses an interceptor group internally:

return new InterceptorGroup<TService>((ComponentRegistration<TService>) this,   
interceptors);

Accordingly, this seems to be a bug in InterceptorGroups.

My workaround (although hacky) is to use my LazyComponentLoader to call AddDescriptor directly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top