I am using inversify, inversify-binding-decorators, and inversify-express-utlis and have problem with express middleware.
I am calling my middleware in this way:
let server = new InversifyExpressServer(container);
...
server.setConfig((app) => {
app.use(validateSession);
});
...
This is my class for ioc registration. Please notice that here I manually register SessionContext in request scope
import DatabaseApi from './../repositories/databaseApi';
import { Container, inject } from "inversify";
import TYPES from "./types";
import { autoProvide, makeProvideDecorator, makeFluentProvideDecorator } from "inversify-binding-decorators";
import { SessionContext } from './../services/session/sessionContext';
let container = new Container();
container.bind<SessionContext>(TYPES.SessionContext).to(SessionContext).inRequestScope();
let provide = makeProvideDecorator(container);
let fluentProvider = makeFluentProvideDecorator(container);
let provideNamed = (identifier: any, name: any) => {
return fluentProvider(identifier)
.whenTargetNamed(name)
.done();
};
export { container, autoProvide, provide, provideNamed, inject };
Now in my middleware I want to get my SessionContext in request scope service in this way:
export async function validateSession(req: Request, res: Response, next: NextFunction) {
try {
...
let sessionContext = container.get<SessionContext>(TYPES.SessionContext);
...
return next();
}
catch (err) {
next(err);
}
}
Service is resolved, but the problem is that if I resolve him in other place I am getting other instance. In request scope doesn't work when I use service inside express middleware. Always resolve gives new instance here. In other words - I want to start scope from express middleware. What I feel is that scope starts later from inversify-express-utils controller.
When dependency is bound
inRequestScope
, every call tocontainer.get
creates a singleton for as long as it's in a "request". https://github.com/inversify/InversifyJS/blob/master/wiki/scope.md#about-inrequestscopeFor example,
The above assert passes because when dependencies for
line
is resolved, they're retrieved in the same request scope. The dependency graph is one like:In the same vein in
validateSession
,sessionContext
is resolved in a separate request scope from that in the controllerI suggest to refactor the middleware from a server level middleware to a controller middleware. This way the dependency graph can be like:
and the same instance of
SessionContext
instance is used in both cases since the dependency is resolved for the request scope of the controller.Bind the middleware to the service container.
Then in the controller inject it.
If you find injecting the middleware to be a rather cumbersome business, you can keep the existing setup then make the
SessionContext
service into a factory or provider returning the same session context service for the same request.https://github.com/inversify/InversifyJS/blob/master/wiki/factory_injection.md