I have an interface and a typed factory interface:
public interface ITransientItem : IDisposable
{
void DoWork(WorkItem item);
}
public interface ITransientItemFactory : IDisposable
{
ITransientItem Create();
void Destroy(ITransientItem item);
}
I Then have an implementation of another interface IDependencyOwner : IDisposable
which is implementend by:
public class DependencyOwner: IDependencyOwner
{
private ITransientItemFactory _factory;
public DependencyOwner(ITransientItemFactory factory)
{
_factory = factory;
}
public void PostWork(WorkItem workItem)
{
ITransientItem item = _factory.Create();
item.DoWork(workItem); //this is done on a seperate thread
_factory.Destroy(item);
}
public void Dispose()
{
//first wait for running items to dispose
//then do disposal stuff
}
}
The DependencyOwner
is held a dependency for yet another object, and there can be many implementations of DependencyOwner, which are resolved with the CollectionResolver
Sub Resolver. but I don't believe that it is relevant to this problem. Its Constructor looks like:
public TopLevel(IDependencyOwner[] dependencies)
Container Registration looks like this:
WindsorContainer container = new WindsorContainer();
container.AddFacility(new TypedFactoryFacility());
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
container.Register(Component.For<TopLevel>());
container.Register(Component.For<IDependencyOwner>().ImplementedBy<DependencyOwner>();
//there will be more IDependencyOwner Implementations in the future
container.Register(Component.For<ITransientItem>().ImplementedBy<TransientItem>()
.LifeStyle.Transient);
container.Register(Component.For<ITransientItemFactory>().AsFactory());
TopLevel top = container.Resolve<TopLevel>();
Everything with the code actually running is fine. The problem comes when it is time to close the program.
The ITransientItemFactory
is getting disposed before DependencyOwner's Dispose method is even called (I have verified this by putting a breakpoint on the very first line of the dispose method and then then checking my log to see that the error is already present). This causes any workItems that were in the middle of processing to fail, and the program crashes rather than ending gracefully.
The exception I get is:
System.ObjectDisposedException: The factory was disposed and can no longer be used. Object name: 'this'.
Why is Windsor not honoring this dependency?
EDIT: I stumbled on this trick here and have been able to confirm that the factory does appear in the dependency graph as a dependency of DependencyOwner.
EDIT 2: I have just implemented the factory myself and removed the typed factory. This solved my problem (As the dependency was honored), but I would rather not do this if I can avoid it. Just for illustrative purposes, the registration in this case becomes:
WindsorContainer container = new WindsorContainer();
//container.AddFacility(new TypedFactoryFacility());
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
container.Register(Component.For<TopLevel>());
container.Register(Component.For<IDependencyOwner>().ImplementedBy<DependencyOwner>();
//there will be more IDependencyOwner Implementations in the future
//No reason to register it anymore, it will never be instantiated by the container
//container.Register(Component.For<ITransientItem>().ImplementedBy<TransientItem>()
//.LifeStyle.Transient);
//container.Register(Component.For<ITransientItemFactory>().AsFactory());
container.Register(Component.For<ITransientItemFactory>()
.ImplementedBy<FactoryImplementation>());
TopLevel top = container.Resolve<TopLevel>();
I’ve contributed a fix for this which shipped in Castle.Windsor 4.1.0! 🎉
https://github.com/castleproject/Windsor/pull/344
https://github.com/castleproject/Windsor/releases/tag/v4.1.0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With