ipjohnson / Grace

Grace is a feature rich dependency injection container library
MIT License
336 stars 33 forks source link

Resolving dependency registered in parent scope with child scope override deps. Resolution context lost. #174

Closed mcdis closed 6 years ago

mcdis commented 6 years ago

I'm using dynamic constructor injection (ConstructorSelection = ConstructorSelectionMethod.Dynamic).

parent scope:

CanvasPlayerImpl depends on ICanvasPlayerSettings child scope:

var child = parent.CreateChildScope(_ =>
   {
       _.ExportInstance<ICanvasPlayerSettings>(new CanvasPlayerSettings());
    });

Exception can't import ICanvasPlayerSettings: child.Locate<ICanvasPlayer>() but: child.Locate<ICanvasPlayerSettings>() executed successfuly.

I suggest that the Grace found "ICanvasPlayer building rule" in the parent scope and then trying to build CanvasPlayerImpl from the one instead use child scope resolution context. For check that I added ICanvasPlayerSettings in the parent scope and the Grace resolved ICanvasPlayer but from the parent scope with wrong settings.

I think the resolution context has to be preserved during resolution

ipjohnson commented 6 years ago

I've added a unit test showing the behavior you are describing and it's working correctly. Can you provide a console app showing the behavior you're seeing and I can try and debug it.

One thing I will say it that when passing through some lifestyles, context is dropped but that's by design (singleton in particular).

If you are on the latest version vs 2017 and have Source Link debugging turned on and just my code turned off you should be able to step into Grace.

mcdis commented 6 years ago

Hi! I've figured out that the Grace crashed when container chain is longer. Look at the code:

   interface ISettings {}
   class Settings : ISettings { }

   interface IConsumer { }
   class Consumer : IConsumer
   {
      public Consumer(ISettings _settings) { }
   }
   class Program
   {
      static void Main()
      {
         var globalScope = new DependencyInjectionContainer(_c => _c.Behaviors.ConstructorSelection = ConstructorSelectionMethod.Dynamic);

         var parentScope = globalScope.CreateChildScope(_ => _.ExportAs<Consumer, IConsumer>());
         var parentScope2 = parentScope.CreateChildScope(); // <-- make the hierarchy longer
         var childScope = parentScope2.CreateChildScope(_ =>
         {
            _.ExportInstance<ISettings>(new Settings());
         });
         childScope.Locate<IConsumer>(); // <-- Crashed
      }
   }
mcdis commented 6 years ago

I found that the above code works properly on the latest 6.4.0-RC685 but crashed on 6.3.4

ipjohnson commented 6 years ago

ok that' makes sense I address an issue that affected nested child scopes here and it is what you described of the child scope being lost in the resolution chain

mcdis commented 6 years ago

Yeah! Waiting for release...

ipjohnson commented 6 years ago

I've released 6.4.0