2
votes

I have a component registered with Castle Windsor which depends on a list of components, each of which is represented by an interface. Castle Windsor is configured similar to the code below.

public class WindsorInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        //Allow the container to resolve all IFooComponent 
        //as IEnumerable<IFooComponent>
        container.Kernel.Resolver
           .AddSubResolver(new CollectionResolver(container.Kernel, false));

        container.Register(
            Component
                .For<IMainService>()
                .ImplementedBy<AwesomeMainService>());

        container.Register(
            Component.For<IFooComponent>()
                .ImplementedBy<CoolFooComponent>()
                .Named(typeof (CoolFooComponent).Name),
            Component.For<IFooComponent>()
                .ImplementedBy<FooComponentWithUnresolvedDependancy>()
                .Named(typeof (FooComponentWithUnresolvedDependancy).Name)
            //....
        );
    }
}

AwesomeMainService depends on an IEnumerable<IFooComponent> like below

public class AwesomeMainService : IMainService
{
    public AwesomeMainService(IEnumerable<IFooComponent> fooComponents) 
    { 
        //I could count the fooComponents here but this is a hack
    }
}

Now if one of the IFooComponents is missing a dependency, or Castle Windsor otherwise encounters an exception while instantiating an IFooComponent, the exception is caught by Castle Windsor and not rethrown. When I resolve the registered instance of IMainService everything appears fine because there is at least on instance of IFooComponent which can be created.

//No exception here because there is at least 1 IFooComponent
var plugin = _container.Resolve<IMainService>(); 

How do I handle this error and shut everything down? I would've thought there would be an event on the Kernel, but there doesn't appear to be.

My Fix:

I created a dynamic parameter for AwesomeMainService which counted the number of IFooProcessors registered. The AwesomeMainService then verified that this matched the number of IFooProcessors provided.

public class AwesomeMainService : IMainService
{
    public AwesomeMainService(IEnumerable<IFooComponent> fooComponents, 
                              int expectedProcessorCount)
    { 
        Verify.That(fooComponents.Count == expectedProcessorCount, 
                    "requestProcessors does not match the expected number " +
                    "of processors provided");
    }
}

Then I added this to the AwesomeMainService registration:

.DynamicParameters((kernel, parameters) =>
    {
        parameters["expectedProcessorCount"] =
            container.Kernel.GetAssignableHandlers(typeof (object))
                .Where(
                    h => h.ComponentModel.Service.UnderlyingSystemType ==
                         typeof (IRequestProcessor))
                .Count();
    }));
1

1 Answers

3
votes

This is a known limitation in Windsor 2.5 and earlier. This scenario will fail-fast in Windsor 3.

In v3 there's also a new event EmptyCollectionResolving which is raised when a component depends on a collection of IFoos but no component for IFoo is registered in the container.