Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

@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");
    }
}

It is preferable to use the ComponentModel construction contributors with the IContributeComponentModelConstruction interface since it is the recommended way of configuring your components further.

To do so, you would implement the interface to specify the changes to apply to configuration

public class ChangeConfiguration : IContributeComponentModelConstruction
{
    public void ProcessModel(IKernel kernel, ComponentModel model)
    {
        // filter your model to match the subset you're interested in
        // change the configuration for matching models
    }
}

Then before registering your components, you just add the class to your container:

container.Kernel.ComponentModelBuilder.AddContributor(new ChangeConfiguration());

All components will then pass through this class, where you can change their configuration. In your case changeing the listener list, etc (I guess this is the previous name of the interceptors)

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