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.
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.
Share Improve this question edited Aug 30, 2019 at 13:27 Nickolay 32.2k13 gold badges110 silver badges194 bronze badges asked Nov 26, 2018 at 10:44 templaristemplaris 2315 silver badges11 bronze badges 1- 1 I guess more people would be able to understand and have a chance to answer the question with an MCVE. For instance I haven't used inversify.js and to see what you mean I'd have to make one myself first, which is a too large time investment for me. – Nickolay Commented Aug 30, 2019 at 13:29
1 Answer
Reset to default 7 +50When dependency is bound inRequestScope
, every call to container.get
creates a singleton for as long as it's in a "request".
https://github./inversify/InversifyJS/blob/master/wiki/scope.md#about-inrequestscope
For example,
const TYPE = {
Coord: Symbol('Coord'),
Line: Symbol('Line'),
};
interface Coord {
x: number;
y: number;
}
interface Line {
p1: Coord;
p2: Coord;
}
@injectable()
class Point implements Coord {
x = 0
y = 0
}
@injectable()
class Coincident implements Line {
@inject(TYPE.Coord) p1: Coord;
@inject(TYPE.Coord) p2: Coord;
}
const container1 = new Container();
container1.bind<Coord>(Coord).to(Coord).inRequestScope();
container1.bind<Line>(TYPE.Line).to(Coincident);
const line = container1.get<Line>(TYPE.Line);
console.assert(line.p1 === line.p2);
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:
root -> line (scope) -> coord (singleton)
In the same vein in validateSession
, sessionContext
is resolved in a separate request scope from that in the controller
// dependency graph in validateSession
root -> sessionContext
// dependency graph in controller
root -> controller -> sessionContext
I suggest to refactor the middleware from a server level middleware to a controller middleware. This way the dependency graph can be like:
// dependency graph in validateSession
root -> controller -> middleware -> sessionContext
// dependency graph in controller
root -> controller -> sessionContext
and the same instance of SessionContext
instance is used in both cases since the dependency is resolved for the request scope of the controller.
import { BaseMiddleware } from "inversify-express-utils";
@injectable()
class ValidateSessionMiddleware extends BaseMiddleware {
@inject(TYPES.SessionContext) private readonly _sessionContext: SessionContext;
public handler(
req: express.Request,
res: express.Response,
next: express.NextFunction
) {
// do something with _sessionContext
next();
}
}
Bind the middleware to the service container.
container.bind<ValidateSessionMiddleware>(ValidateSessionMiddleware).toSelf();
Then in the controller inject it.
@injectable()
@controller("/")
class MyController {
@httpGet("/", ValidateSessionMiddleware)
public async index() {
}
}
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./inversify/InversifyJS/blob/master/wiki/factory_injection.md
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745279700a4620220.html
评论列表(0条)