views:

513

answers:

2

If I have defined in config:

container.Register(
   Component.For<X.Y.Z.IActivityService>()
            .ImplementedBy<X.Y.Z.ActivityService>()
            .ServiceOverrides(ServiceOverride.ForKey("Listeners").Eq(new [] { typeof(X.Y.Z.DefaultActivityListener).FullName }))
            .LifeStyle.Transient
);

and I wish to extend this configuration and add a new item to the Listeners array property such that the final configuration is effectively:

container.Register(
   Component.For<X.Y.Z.IActivityService>()
            .ImplementedBy<X.Y.Z.ActivityService>()
            .ServiceOverrides(ServiceOverride.ForKey("Listeners").Eq(new [] { typeof(X.Y.Z.DefaultActivityListener).FullName, "MyOtherListenerID" }))
            .LifeStyle.Transient
);

must I know the contents of the "array" when first registering the component, or can I retrieve the component registration and add to it?

I wish to implement my config using the decorator pattern such that I can build my container, and then extend it as needed for different scenarios. This means I need to be able to access the already configured components and add to them.

Was thinking of having a class DefaultConfig which return the default setup and then one of more "DecoratedConfig" classes, that would extend the default config.

So I would have

IWindsorContaner c = new DecoratedConfig(new DefaultConfig()).InitialiseContainer();

DefaultConfig would set up the ActivityService with a DefaultActivityListener (as shown in example).

DecoratedConfig would recognise that ActivityService had been created and add its own Listener implementation to the Listeners array on ActivityService.

Thanks.

A: 

Subscribe to the Kernel.ComponentModelCreated event. You can change any component parameter from there. See this. It doesn't have to be a facility who does this, but it's convenient.

Mauricio Scheffer
CompoentModel modification is the way to go. See below test method.
crowleym
A: 

@mausch, adusting the ComponentModel configuration appears to be the solution.

The below test effecitvely does what I require without having to hook in to the ComponentModelCreatedEvent so I can make the changes even after the component model is created.

I will wrap the functionality as an extension method, and try and fit to a fluent API.

[TestMethod]
public void ArrayPropertyTestApi3()
{
    using (Castle.Windsor.WindsorContainer container = new Castle.Windsor.WindsorContainer())
    {
        container.Register(Component.For<Components.A>().ServiceOverrides(ServiceOverride.ForKey("I").Eq(new[] { typeof(Components.B).FullName })));
        container.Register(Component.For<Components.B>());
        container.Register(Component.For<Components.C>());

        IHandler h = container.Kernel.GetHandler(typeof(Components.A));
        if (h != null)
        {
            var config = h.ComponentModel.Configuration;
            if (config != null)
            {
                var items = config.Children.Single(c => c.Name == "parameters")
                                  .Children.Single(c => c.Name == "I")
                                  .Children.Single(c => c.Name == "list")
                                  as MutableConfiguration;

                items.Children.Add(new MutableConfiguration("item", string.Format("${{{0}}}", typeof(Components.C).FullName)));
            }
        }

        Components.A svc = container.Resolve<Components.A>();
        Assert.IsTrue(svc.I.Length == 2);
        Assert.IsTrue(svc.I[0].Name == "B");
        Assert.IsTrue(svc.I[1].Name == "C");
    }
}
crowleym