inversify / InversifyJS

A powerful and lightweight inversion of control container for JavaScript & Node.js apps powered by TypeScript.
http://inversify.io/
MIT License
11.21k stars 715 forks source link

Inject container in dependency #1486

Open Deathrage opened 1 year ago

Deathrage commented 1 year ago

Expected Behavior

Generally IoC container allow self injection. I will demonstrate in C#. This is to demonstrate that this approach is common and supported by other frameworks (example below demonstrate .NET Core's IoC container).

class Foo {
    public IServiceProvider Provider { get; }

    public Foo(IServiceProvider provider) // this is DI container 
    {  
          Provider = provider;
     }
}

IServiceCollection services = new ServiceCollection();
services.AddTransient<Foo>(); // register to DI
IServiceProvider provider = services.BuildServiceProvider(); // build container;

var foo = provider.GetService<Foo>();

foo.Provider == provider ; // true

In this case, constructor recieve instance that is constructing given type. This means that child containers propagte their own instance.

var foo1 = provider.GetService<Foo>();
var childProvider = provider.CreateScope().ServiceProvider; // Create child scope/container
var foo2 = provider.childProvdier <Foo>();

foo1.Provider == foo2.Provider; //false
foo2.Provider = childProvider; // true

Usecase in TypeScript:

cosnt container = new Container();

@injectable()
class Foo { 
   constructor(container: Container) {
       this.container= container;
   }
}

container.bind(Foo).toSelf();

const foo1 = container.get(Foo);
foo1.container === container; // true

const childContainer = container.createChild();
cosnt foo2 = childContainer.get(Foo);

foo1.container === foo2.container; // false
foo2.container === childContainer; // true

Current Behavior

Uncaught Error: No matching bindings found for serviceIdentifier: Container at _validateActiveBindingCount (planner.js:59:1) at _getActiveBindings (planner.js:45:1) at _createSubRequests (planner.js:86:1) at planner.js:110:1 at Array.forEach () at planner.js:109:1 at Array.forEach () at _createSubRequests (planner.js:89:1) at plan (planner.js:131:1) at container.js:598:31

Your Environment

vhiairrassary commented 1 year ago

👍 We are encountering the same issue while migrating from typed-inject which provides this feature. Did you find a workaround @Deathrage?

Deathrage commented 1 year ago

@vhiairrassary yes

container.bind(Container).toDynamicValue(ctx => ctx.container as Container);

But this is somewhat a hack as ctx.container is not class Container but interface Container and I cast it to the class (watchout, you cannot be sure that ctx.container is an instance of that class as it might be a different subtype; However, as of now it is instnace of that class).

vhiairrassary commented 1 year ago

Thank you so much 🤩 Hopefully the feature will be implemented at some point in the project 🤞