Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypedFactory Disposes Before Component Using it As a Dependency

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>();
like image 658
pquest Avatar asked Nov 09 '22 23:11

pquest


1 Answers

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

like image 53
jnm2 Avatar answered Nov 15 '22 07:11

jnm2