InversifyJS icon indicating copy to clipboard operation
InversifyJS copied to clipboard

getAllAsync fails when used with .toService and async .toDynamicValue

Open humodz opened this issue 1 year ago • 0 comments

I've provided a full example in this gist: https://gist.github.com/humodz/364f0046eaae1aa724767da934719f64

But, in a nutshell, getAllAsync can't resolve dynamic dependencies if .toService was used to bound the requested services

container.bind(Database).toDynamicValue(async () => { /* ... */ });
container.bind(Service1).toSelf(); // Service1 depends on Database
container.bind('services').toService(Service1);

const services = await container.getAllAsync('services');
// throws: You are attempting to construct Service1 in a synchronous way but it has asynchronous dependencies.

The same problem occurs when using @multiInject

Expected Behavior

getAllAsync should be able to resolve all async dependencies, even transitive ones, just like getAsync

Current Behavior

getAllAsync is only able to resolve the requested services asynchronously, but not their dependencies

Steps to Reproduce (for bugs)

https://gist.github.com/humodz/364f0046eaae1aa724767da934719f64

Additional Issues

In the gist, if I uncomment container.bind(Database).toSelf(); and comment the .toDynamicValue call, then two instances of Database and two instances of Service1 are created, even though the default scope is Request. Is this intended? From taking a look at https://github.com/inversify/InversifyJS/blob/master/test/features/transitive_bindings.test.ts, it feels that the intended behavior would be for a single instance of each to have been created.

Context

In the end, I'm trying to find a way to get all Controllers in the application. My idea was to try:

container.bind('controllers').toService(Controller1);
container.bind('controllers').toService(Controller2);
// ... etc

const controllers = await container.getAllASync('controllers');

But then I ran into the aforementioned issue

Your Environment

$ node --version
v18.18.0
$ npm why inversify
[email protected]

Stack trace

Error: You are attempting to construct 'class{constructor(database){this.database=database;console.log("new Service1")}}' in a synchronous way
 but it has asynchronous dependencies.
    at Container._getButThrowIfAsync (/home/hugo/projects/scratch/hello-fastify/node_modules/inversify/lib/container/container.js:601:19)
    at Container.get (/home/hugo/projects/scratch/hello-fastify/node_modules/inversify/lib/container/container.js:374:21)
    at Binding.dynamicValue (/home/hugo/projects/scratch/hello-fastify/node_modules/inversify/lib/syntax/binding_to_syntax.js:102:75)
    at /home/hugo/projects/scratch/hello-fastify/node_modules/inversify/lib/resolution/resolver.js:94:119
    at tryAndThrowErrorIfStackOverflow (/home/hugo/projects/scratch/hello-fastify/node_modules/inversify/lib/utils/exceptions.js:31:16)
    at _resolveFactoryFromBinding (/home/hugo/projects/scratch/hello-fastify/node_modules/inversify/lib/resolution/resolver.js:94:61)
    at _getResolvedFromBinding (/home/hugo/projects/scratch/hello-fastify/node_modules/inversify/lib/resolution/resolver.js:112:22)
    at /home/hugo/projects/scratch/hello-fastify/node_modules/inversify/lib/resolution/resolver.js:127:22
    at _resolveInScope (/home/hugo/projects/scratch/hello-fastify/node_modules/inversify/lib/resolution/resolver.js:121:14)
    at _resolveBinding (/home/hugo/projects/scratch/hello-fastify/node_modules/inversify/lib/resolution/resolver.js:126:12)

humodz avatar Apr 17 '24 16:04 humodz