Andy
Andy

Reputation: 3696

Circular dependencies in StructureMap - can they be broken with property injection?

I've got the simplest kind of circular dependency in structuremap - class A relies on class B in its constructor, and class B relies on class A in its constructor. To break the dependency, I made class B take class A as a property, rather than a constructor argument, but structuremap still complains.

I've seen circular dependencies broken using this method in other DI frameworks - is this a problem with Structuremap or am I doing something wrong?

Edit: I should mention that class B's property is an array of class A instances, wired up like this:

x.For<IB>().Singleton().Use<B>().Setter(y => y.ArrayOfA).IsTheDefault();

Just to clarify, I want the following sequence of events to occur:

And I want all this to happen using autowiring, if possible...

Edit 2: Here's a simplified example that uses explicit wiring up:

interface ILoader { }
interface ILoaderManager { }

class Loader : ILoader
{
    public Loader(ILoaderManager lm) { }
}
class LoaderManager : ILoaderManager
{
    public ILoader Loader { get; set; } // Was an array, but same circular dependency appears here
}

ObjectFactory.Configure
(
    x =>
    {
        x.For<ILoader>.Singleton().Use<Loader>();
        x.For<ILoaderManager>().Singleton().Use<LoaderManager>().OnCreation((c, a) => a.Loader = c.GetInstance<ILoader>());
    }
);

Validating the configuration causes "Bidirectional Dependency Problem detected with RequestedType: IocTest2.ILoader..."

Upvotes: 9

Views: 11101

Answers (3)

Javier
Javier

Reputation: 2169

StructureMap can handle bi-directional situation also with a workaround using Lazy resolution.

If you have a simple situation like ClassA that depends on ClassB and ClassB that depends of ClassA, then you can choose one of them and convert the dependency as a Lazy dependency. This way worked for me and that error never appeared again..

public class ClassA
{
    private readonly Lazy<IClassB> _classB;

    public ClassA(Lazy<IClassB> classB)
    {
        _classB = classB;
    }

    public IClassB ClassB => _classB.Value;
}

public class ClassB 
{
    public IClassA _classA { get; set; }

    public ClassB (IClassA classA)
    {
        _classA = classA;
    }
}

More info here: http://structuremap.github.io/the-container/lazy-resolution/

Upvotes: 6

Joshua Flanagan
Joshua Flanagan

Reputation: 8557

The closest you can get is something like this:

x.For<IB>().Use<B>()
    .OnCreation((ctx, instance) =>
    {
        instance.ArrayOfA = new IA[] {new A(instance) };
    });

If A has other dependencies that you want to resolve from the container, you can retrieve them from ctx within the OnCreation lambda.

Upvotes: 3

statenjason
statenjason

Reputation: 5190

StructureMap is likely performing Setter Injection where it will populate public settable properties on an object it's resolving. According to the documentation,

By default, all public "Setters" are optional, meaning that these setters will only be set if they are explicitly configured for a specific Instance

So have you by chance set up the properties to be auto wired? If so, you'll still have the circular dependency issue.

Edit: I see that you have. In your instance because B has A[] injected, StructureMap must resolve each A's dependency for a B that needs A[], and so on...

Upvotes: 1

Related Questions