Search code examples
c#ninjectfactory-patternstrategy-pattern

Cyclical dependency error when creating Strategy pattern using ninject


This is my dependancy injection setup:

dIcontainer.Bind<DBContext>().ToSelf().InRequestScope();

//Repository accepts a constructor parameter DBContext
dIcontainer.Bind<IRepository1, Repository1>();   
dIcontainer.Bind<IRepository2, Repository2>();

//All strategies accepts a constructor parameter of a repository interface
//There is one strategy per repository
dIcontainer.Bind(x => x.FromThisAssembly().SelectAllClasses().InheritedFrom<IStrategy>().BindSingleInterface());

//The factory accepts a constructor parameter of IEnumerable<IStrategy>
dIcontainer.Bind<StrategyFactory>().ToSelf();

The implementation of the factory:

public class StrategyFactory
{
    private IEnumerable<IStrategy> _strategies;

    public StrategyFactory(IEnumerable<IStrategy> strategies)
    {
        _strategies = strategies;
    }

    public IStrategy GetStrategy(string keyToMatch)
    {
        return _strategies.Single(strategy => strategy.IsStrategyMatch(keyToMatch));
    }
}

The repositories and the context are in a separate project.

When I call the GetStrategy method (resolving the DI tree) i get this error:

Error activating IStrategy using binding from IStrategy to Strategy1 A cyclical dependency was detected between the constructors of two services.

If I new up the repositories in each the strategy constructors instead:

public Strategy1()
{
     _repository = new Repository1(new DBContext());           
}

I get a perfect list of strategies in my factory and can resolve the relevant strategy based on the keyToMatch. What am I doing wrong?

Lets me know if the question is too compact.


Solution

  • A Cyclical Dependency means something like:

    Strategy1 needs Repository1 needs Foobar needs Strategy1 needs (and on and on and on, sorry but there's not enough disk space in the world to finish this example properly)

    So you see, resolving this would end up in a StackoverflowException. The resolver would turn in cycles resolving Strategy1 for Foobar for Repository1 for Strategy1 for Foobar for ...

    You need to identify the cycle and break it. Either you actually really break it, otherwise you might get away with making one component use a scope like InSingletonScope() or InRequestScope() (as applicable) and lazy injecting it instead of injecting it into the ctor. You can use Ninject.Extensions.Factory and Lazy<T> or Func<T> for that.