views:

144

answers:

1

I'm trying to execute an action on a resolved component before it is returned as a dependency to the application.

For example, with this graph:

public class Foo : IFoo { }

public class Bar {
  IFoo _foo;
  IBaz _baz;
  public Bar(IFoo foo, IBaz baz) {
    _foo = foo;
    _baz = baz;
  }
}

When I create an instance of IFoo, I want the container to instantiate Bar and pass the already-resolved IFoo to it, along with any other dependencies it requires. So when I call:

var foo = container.Resolve<IFoo>();

The container should automatically call:

container.Resolve<Bar>(); // should pass foo and instantiate IBaz

I've tried using OnCreate, DynamicParameters and UsingFactoryMethod, but the problem they all share is that they don't hold an explicit reference to the component: DynamicParameters is called before IFoo is instantiated. OnCreate is called after, but the delegate doesn't pass the instance. UsingFactoryMethod doesn't help because I need to register these components with TService and TComponent.

Ideally, I'd like a registration to look something like this:

container.Register<IFoo, Foo>((kernel, foo) => kernel.Resolve<Bar>(new { foo }));

Note that IFoo and Bar are registered with the transient life style, which means that the already-resolved instance has to be passed to Bar - it can't be "re-resolved".

Is this possible? Am I missing something?

+1  A: 

It seems that this is what you want:

public interface IFoo {}
public class Foo : IFoo {}
public class Bar {
    public IFoo BarFoo { get; private set;}

    public Bar(IFoo foo) {
        BarFoo = foo;
    }

    public void DoSomething() {
        Console.WriteLine("Initializing");
    }
}

[Test]
public void Create() {
    var container = new WindsorContainer();
    var initialized = false;
    container.Register(Component.For<IFoo>().ImplementedBy<Foo>().LifeStyle.Transient
        .OnCreate((kernel, foo) => {
            var bar = kernel.Resolve<Bar>(new {foo});
            Assert.AreSame(foo, bar.BarFoo);
            bar.DoSomething();
            initialized = true;
        }));
    container.Register(Component.For<Bar>().LifeStyle.Transient);
    var f = container.Resolve<IFoo>();
    Assert.IsTrue(initialized);
}

It's actually almost a duplicate of this other question.

Mauricio Scheffer
I've tried similar code. The expectation here is that passing the anonymous [new {foo}] would avoid creating resolving a new IFoo instance when resolving Bar, but my experience was different. The container kept creating new IFoo instances. Maybe I did something wrong. I'll try it again and let you know.
shovavnik
By the way, I'd seen the other question, but there are a couple of significant differences: 1. I don't need to hold an explicit reference to the Bar instance after IFoo is resolved. 2. Bar has a dependency on the transient IFoo and also on the global IBaz.
shovavnik
I've figure it out. Your code initially produced a cyclic dependency error. The problem was that I forgot to account for Windsor's property injection, as BarFoo (in real life) has a public setter. Once I added the OptionalPropertyInjectionFacility, your code worked.
shovavnik
@shovanik: the code works for me just as I posted it. The test passes.
Mauricio Scheffer

related questions