Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolving dependencies in activation handler within request scope #820

Open
ballwood opened this issue Mar 15, 2018 · 4 comments
Open

Resolving dependencies in activation handler within request scope #820

ballwood opened this issue Mar 15, 2018 · 4 comments

Comments

@ballwood
Copy link

ballwood commented Mar 15, 2018

Hi,

I'm using activation handlers to provide a cross cutting logging concern like in the example below. Is there anything in the context provided to the activation handler that I can use to get a dependency and make sure it respects the scope that has been defined in the original container....using get just creates a new instance which means I'm creating 2 instances of the logger class per request.

Thanks :)

interface Katana {
    use: () => void;
}

@injectable()
class Katana implements Katana {
    private logger: Logger;

    constructor(@inject("Logger") logger: Logger) {
        this.logger = logger;
    }

    public use() {
        this.logger.log("Used Katana!");
    }
}

interface Ninja {
    katana: Katana;
}

@injectable()
class Ninja implements Ninja {
    public katana: Katana;
    public constructor(@inject("Katana") katana: Katana) {
        this.katana = katana;
    }
}

@injectable()
class Logger {
    private id: number;

    constructor () {
        this.id = Math.random();
    }

    log(message: string) {
        console.log(this.id, message);
    }
}

container.bind<Ninja>("Ninja").to(Ninja).inRequestScope();
container.bind<Logger>("Logger").to(Logger).inRequestScope();

container.bind<Katana>("Katana").to(Katana).onActivation((context, katana) => {
    let handler = {
        apply: function(target, thisArgument, argumentsList) {
            const logger = context.container.get<Logger>("Logger")

            logger.log(`Starting: ${new Date().getTime()}`);
            let result = target.apply(thisArgument, argumentsList);
            logger.log(`Finished: ${new Date().getTime()}`);
            return result;
        }
    };
    katana.use = new Proxy(katana.use, handler);
    return katana;
});

const x = container.get<Ninja>("Ninja");
x.katana.use();

// prints 0.9743319482800241 'Starting: 1521117423975'
// prints 0.11081344599818421 'Used Katana!'
// prints 0.9743319482800241 'Finished: 1521117423991'
@InExtremaRes
Copy link

@ballwood Did you figure it out? I'm facing something similar and the only thing has worked for me right now is using context.plan.rootRequest.requestScope, which is a Map whose values are the instances created for the current scope. Have you find something different?

@tonyhallett
Copy link
Contributor

The 'get' methods start a new request so you will receive a new Logger. Using the context.plan.rootRequest.requestScope is the correct way of achieving what you want.

@BurningEnlightenment
Copy link

@notaphplover would it be possible to add a get() overload to the new v7 ResolutionContext which accepts an existing scope reference? This would allow users to manually forward the scope.

@notaphplover
Copy link
Member

Hey @BurningEnlightenment, I need to think about it. I honestly believe it makes sense to make internal subrequests look like the same request for the user, but if we go for this it should be transparent to the user and I would like to avoid some performance issues I am thinking about.

Having said that, one workaround in v7 is using resolved values. They don't make subrequests so the request scope would be the same one.

As said, I do need to carefully think about it before going for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

5 participants