Search code examples
c#dependency-injectioninversion-of-controlcastle-windsor

Multiple Chained Dependencies, Some of Which Require Run Time Arguments


I am setting up dependency injection for a Web Service project with Castle Windsor. I have some classes that depend on runtime arguments that are also dependencies for other classes. I have a somewhat working solution for this problem, but it gets messy as the dependency chain gets longer with runtime arguments. I am trying to implement a more elegant solution.

I have some of these dependencies resolved with a TypedFactoryFacility that I am registering like this:

public interface ISomeClassFactory
{
   ISomeClass Create(ISomeSimpleDependency dependency);
}

...

public interface ISomeSimpleDependencyFactory
{
   ISomeSimpleDependency Create(string runtimeArgument);
}

...

public void Install(IWindsorContainer container, IConfigurationStore store)
{
    container.Register(
        Component.For<ISomeClass>().ImplementedBy<SomeClass>(),
        Component.For<ISomeClassFactory().AsFactory());
    container.Register(
        Component.For<ISomeSimpleDepencency>().ImplementedBy<SomeSimpleDependency>(),
        Component.For<ISomeSimpleDepencencyFactory().AsFactory());
}

And called like this:

public void WebServiceMethod(string runtimeArgument)
{
    ISomeSimpleDependency someSimpleDependency = container.Resolve<ISomeSimpleDependencyFactory>().Create(runtimeArgument);
    ISomeClass someClass = container.Resolve<ISomeSimpleClassFactory>().Create(someSimpleDependency);
    // the rest of the method
}

Thgis works, but there are some problems with this. Even if I do not need to call any methods on someSimpleDependency, I have to instantiate it to have it as a dependency for someClass (this is the original problem that I was tring to solve by implementing dependency injection in this project). Furthermore, things get more tricky when I have a class that has a runtime dependency that is several layers down in the dependency chain:

ISomeClass -> IDependency1 -> IDependency2 -> IDependency3 -> runtimeArgument

Is there any way to instantiate someClass with out having factory methods chaining up from dependency 3?

public void WebServiceMethod(string runtimeArgument)
{
    IDependency3 dependency3= container.Resolve<IDependency3Factory>().Create(runtimeArgument);
    IDependency2 dependency2 = container.Resolve<IDependency2Factory>().Create(dependency3);
    IDependency1 dependency1 = container.Resolve<IDependency1Factory>().Create(dependency2);

    ISomeClass someClass = container.Resolve<ISomeClassFactory>().Create(dependency1);

}

Solution

  • I am not sure if this is the best solution to this problem, but I was able to get a working solution using Scoped Lifestyle.

    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component.For<ISomeClass>().ImplementedBy<SomeClass>());
        container.Register(Component.For<IDependency1>().ImplementedBy<Dependency1>());
        container.Register(
            Component.For<ISomeSimpleDepencency>().ImplementedBy<ISomeSimpleDepencency>().LifeStyleScoped(),
            Component.For<ISomeSimpleDepencencyFactory().AsFactory());
    }
    

    And in the invoking method

    public void WebServiceMethod(string runtimeArgument)
    {
        using (container.BeginScope())
        {
            IDependency3 dependency3= container.Resolve<ISomeSimpleDepencencyFactory>().Create(runtimeArgument);
    
            ISomeClass someClass = container.Resolve<ISomeClass>());
        }
    }
    

    The instance using the run time parameter will be retained in the scope. I'm not marking this as the answer because I'm not yet convinced that there isn't a better solution