David Leonhartsberger
David Leonhartsberger

Reputation: 193

Structuremap uses static property injection config for each new Container instance

I am working on a legacy application and my current goal is to set up some integration test which also take use of structure map. So far I had no problem with using SM for unit testing and production code for almost a year. But unfortunately we are forced to use setter injection cos our BOs are real dependency beast (a lot of these objects have circular dependencies on others)

Our workout for this was to use a two step approach: Were we first created all of these objects without inject properties (which cause this circular dependencies) and after wards build up those objects (inject dependency objects through their properties) when they were already created. (See example class A, B and Logic which have circular dependencies)

This worked fine till now -> When we run lets say 3 integration tests after each other than only the first "turns green" the other test are throwing execptions when structuremap tries to create the instances (in the GetManagerInstances) methods.

I am guessing SM holds its property injection config static.

Definitions

internal interface IM { }

internal interface ILogic { }

internal interface IMA : IM { }

internal interface IMB : IM { }

internal class A : IMA
{
    public A() { Console.WriteLine("A"); }

    public IMB BInstance { get; set; }
}

internal class B : IMB
{
    public B() { Console.WriteLine("B"); }

    public IMA AInstance { get; set; }

    public ILogic Logic { get; set; }
}

internal class Logic : ILogic
{
    public Logic() { Console.WriteLine("Logic"); }

    public IMA AInstance { get; set; }
}

Initialization

private static IContainer _container;

while (true)
{
   Initialize();
}

internal static void Initialize()
{
   _container = new Container(c =>
   {
      c.For<ILogic>().Singleton().Use<Logic>();

      c.For<IMB>().Singleton().Use<B>();
      c.For<IMA>().Singleton().Use<A>();
   });

   // All managers are created and afterwards properties are set to avoid a circular build stack.
   List<object> managerInstances = GetManagerInstances();

   // After the manager instances are created the dependencies are injected in the properties.
   BuildUpManagersUsingPropertyInjection(managerInstances);
}

   private static List<object> GetManagerInstances()
   {
     List<object> managerInstances = new List<object>();

     foreach (Type pluginType in new List<Type> { typeof(IMA), typeof(IMB) })
     {
        try
        {
           managerInstances.Add(_container.GetInstance(pluginType));
        }
        catch (Exception ex)
        {
           // exception on second test run -> see below
        }
     }

     return managerInstances;
   }

   private static void BuildUpManagersUsingPropertyInjection(List<object> managerInstances)
   {
      _container.Configure(x => x.SetAllProperties(c =>
      {
         // configure the property injection for all managers
         c.Matching(prop => typeof(IM).IsAssignableFrom(prop.PropertyType));

         // client logic is also used by managers
         c.TypeMatches(type => type.Equals(typeof(ILogic)));
      }));

      _container.BuildUp(_container.GetInstance<ILogic>());
      managerInstances.ForEach(x => _container.BuildUp(x));
   }    

Result

StructureMap Exception Code: 295 Bidirectional Dependency Problem detected with RequestedType: StructureMapTests.IMA, Name: 237b6fb1-7dee-4f09-b663-c33bb793afc6, ConcreteType: StructureMapTests.A. The BuildStack is: 1.) RequestedType: StructureMapTests.IMA, Name: 237b6fb1-7dee-4f09-b663-c33bb793afc6, ConcreteType: StructureMapTests.A 2.) RequestedType: StructureMapTests.IMB, Name: ad692281-cd27-493c-8271-3dcf86bacd41, ConcreteType: StructureMapTests.B Exception when building *

Analysis

The output for the First test run is:
A
B
Logic --> Everything OK

The output for the Second test run is: A
B
Exception when building instances
B
A
Exception when buildinginstances
Logic
A
B --> REPEATING ENDLESS

Please help :(

EDIT I'm targeting 4.0 .Net framework and using StructureMap release 2.6.2

Upvotes: 4

Views: 1726

Answers (2)

Joshua Flanagan
Joshua Flanagan

Reputation: 8557

I have confirmed this is a bug in the current version of StructureMap (as of January 2011). The setter injection policies are in fact being incorrectly shared between containers. The issue has been reported to the StructureMap mailing list.

Upvotes: 4

David Leonhartsberger
David Leonhartsberger

Reputation: 193

this does solve the problem with the circular dependency (no exception is thrown when initializing) but the properties are not filled correctly.

A.BInstance = null
B.AInstance = null
Logic.AInstance = null

the properties should be set to the correct instance!

Upvotes: 0

Related Questions