Castle Windsor: How can I update a components registration

倖福魔咒の 提交于 2019-12-12 13:59:34

问题


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.


回答1:


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.




回答2:


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



回答3:


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)



来源:https://stackoverflow.com/questions/938898/castle-windsor-how-can-i-update-a-components-registration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!