Search code examples
castle-windsor

Can't call component method from Castle Windsor OnCreate


I'm using Castle Windsor, which generally rocks, however I want it to call a method on my component when it is created and seem to have hit a limitation with OnCreate. For exaxmple:

interface IService1
{
    void op1();
}

interface IService2
{
    void op2();
}

class MyComponent : IService1, IService2
{
    public void Init() // not part of either service
    {
    }

    public void op1()
    {
    }

    public void op2()
    {
    }
}

// I want to call the component's Init() method when it's created, which isn't part of the service contract
container.Register(Component.For<IService1, IService2>().ImplementedBy<MyComponent>().OnCreate(s => s.Init()));

// I could call something from IService1
container.Register(Component.For<IService1, IService2>().ImplementedBy<MyComponent>().OnCreate(s => s.op1()));

// But I can't call anything from any of the other services
container.Register(Component.For<IService1, IService2>().ImplementedBy<MyComponent>().OnCreate(s => s.op2()));

The first registration won't compile, complaining that it "cannot resolve symbol Init" because the instance passed to the delegate is of type IService1. OnCreate seems a bit limited to me, as in the third case when there are multiple services exposed it only allows you to bind to the first one you declare. I'd have to swap IService1 and IService2 around in order to call op2, but that's just moving the problem around.

Why isn't the type passed in the delegate that of the component being registered? Then I'd be free to call whatever method I like. Is there a way around this? Assume I can't put the Init() code in the component's constructor.


Solution

  • Don't be constrained by the strongly typed nature of C#

    Yes, the way the API is constructed it's based off of the first service of the component but you can always cast it down to its actual type (or a secondary service)

    .OnCreate(s => ((MyComponent)s).Init())
    

    Alternatively, implement Castle.Core.IInitializable or System.ComponentModel.ISupportInitialize (if you don't want your components to reference Windsor) and then you won't need .OnCreate() at all.

    For future reference, here's the relevant documentation.