Question

Quick Background: I've finished (mostly) reading Mark Seemann's "Depdendency Injection in .NET" and am ready to become a DI ninja. I've refactored my codebase to use constructor injection, wired up my objects using Windsor, and SUCCESS!

... except not. My program originally displayed several forms throughout it's lifetime, and this was originally accomplished by new()ing them all up as needed. However, now that I'm a NIT (ninja-in-training) I know that new() is evil and must be banished to the composition root.

The problem: My first end-to-end use test involved displaying my "main" window to the user. This window can be closed and a new version can be brought up again later. This worked fine in the post-DI codebase until it came time to display the form for a second time. crash. The form had already been disposed. In wiring up my DI container I told it to use the Form's class to implement a specific interface and as should be expected it gave that object a singleton lifetime.

The question: So I'm pretty sure the way to fix this is to not have a dependency on the interface that the form implemented, but rather have a dependency on a factory for that interface. This is where I'm confused on how to proceed.

My first thought is to create a factory with the same constructor signature as the form, store all of those dependencies, and then new() up a form whenever one is asked for. However, this feels like poor-man's DI and I've already gone through the hassle of registering all my stuff with the Windsor container. So that leads me to...

My second thought was to instead create a factory that takes the DI container as a dependency and then just .Resolve()s what I need each time (using the transient lifestyle this time). I suspect that I'd hook into the .Closed event and release there (following the Register-Resolve-Release pattern).

The real question: I like the idea of my second thought, but for some reason it feels like a hack. I don't know if that's because it is (and there is a better way) or if my spidey-senses just aren't tuned for DI yet. So, bottom line, is the "second thought" a valid approach or is it a code smell?

Also, if I use this approach with something that doesn't provide a way to hook into a "closed" event then how should I design the release mechanism such that the factory reminds/encourages me to release the object when done? (at some point I'll probably forget otherwise...)

Thanks!

Was it helpful?

Solution

What ended up working for me while still keeping my lower layers unaware of the DI container was to create a factory interface at the lower layer, but then implement that factory at my composition root layer.

i.e.:

namespace MyApp.InterfaceLayer
{
    public interface IFormFactory
    {
        IForm GetForm();
    }
}
namespace MyApp.CompositionRoot
{
    class FormFactory : IFormFactory
    {
        Castle.Windsor.IWindsorContainer Container { get; set; }

        public FormFactory(Castle.Windsor.IWindsorContainer container)
        {
            Container = container;
        }
        public IForm GetForm()
        {
            return Container.Resolve<IForm>();
        }
    }
}

I would then of course register my form that implements IForm using a transient lifestyle and would register my container as an IWindsorContainer.

So far this has been working like a champ!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top