inversify / InversifyJS

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

Make decorators available in param (context: interfaces.Context) of toDynamicValue #633

Closed stephandrab closed 6 years ago

stephandrab commented 7 years ago

I would like to have a possibility to declaratively define construction parameters of injected entities.

Expected Behavior

I would like to be able to constsruct a logger like this:

@inject("Logger") @named("logger context") logger: Logger;

Current Behavior

I found two solutions, that are possible with the current (v4.3.0) implentation:

Possible Solution

My preferred solution is to use the value from e.g. the @named-decorator in toDynamicValue to construct the entity. Currently I could not find the value in the provided interfaces.Context-object. So a solution would be to extend this information somehow, so one is able to use it there:

container.bind<Logger>("Logger").toDynamicValue(context => new Logger(context.getNameSomehow()));

With the above 'generic' implementation, one could inject entities like this without additional code:

@inject("Logger") @named("logger context 1") logger: Logger;
@inject("Logger") @named("logger context 2") logger: Logger;

I hope I didn't miss something in the docs (interfaces.Context or other APIs)!

Thanks in advance & Cheers, Stephan

stephandrab commented 7 years ago

I just found #576, which may be related to this

remojansen commented 6 years ago

Hi @stephandrab

This is now implemented by https://github.com/inversify/InversifyJS/pull/719 and available in inversify@4.8.0 🎉

You can now access the current request via context.currentRequest. The following code snippet is an example:

@injectable()
class Logger {
    public named: string;
    public constructor(named: string) {
        this.named = named;
    }
}

const container = new Container();

const TYPE = {
    Logger: Symbol.for("Logger")
};

container.bind<Logger>(TYPE.Logger).toDynamicValue((context) => {
    const namedMetadata = context.currentRequest.target.getNamedTag();
    const named = namedMetadata ? namedMetadata.value : "default";
    return new Logger(named);
});

const logger1 = container.getNamed<Logger>(TYPE.Logger, "Name1");
const logger2 = container.getNamed<Logger>(TYPE.Logger, "Name2");

expect(logger1.named).to.eq("Name1");
expect(logger2.named).to.eq("Name2");