我正在使用inversify,inversify-binding-decorators和inversify-express-utlis,并且对快速中间件有疑问。
我以这种方式调用中间件:
let server = new InversifyExpressServer(container);
...
server.setConfig((app) => {
app.use(validateSession);
});
...
这是我的IOC注册课程。请注意,这里我是在请求范围内手动注册SessionContext
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 };
现在在中间件中,我想在请求范围服务中获取SessionContext 通过这种方式:
export async function validateSession(req: Request, res: Response, next: NextFunction) {
try {
...
let sessionContext = container.get<SessionContext>(TYPES.SessionContext);
...
return next();
}
catch (err) {
next(err);
}
}
服务已解决,但问题是,如果我在其他地方解决他,我将获得其他实例。当我在快速中间件中使用服务时,请求范围不起作用。始终解决在这里给出了新实例。换句话说-我想从快速中间件开始范围。我的感觉是,范围稍后从inversify-express-utils控制器开始。
答案 0 :(得分:2)
绑定依赖项inRequestScope
时,每次对container.get
的调用都会创建一个单例,只要它在“请求” 中。
https://github.com/inversify/InversifyJS/blob/master/wiki/scope.md#about-inrequestscope
例如,
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);
通过以上断言是因为解决line
的依存关系时,将在相同的请求范围内对其进行检索。依赖图就像这样:
root -> line (scope) -> coord (singleton)
在validateSession
中,sessionContext
在与控制器中不同的请求范围内被解析
// dependency graph in validateSession
root -> sessionContext
// dependency graph in controller
root -> controller -> sessionContext
我建议将中间件从服务器级中间件重构为控制器中间件。这样,依赖图可以像这样:
// dependency graph in validateSession
root -> controller -> middleware -> sessionContext
// dependency graph in controller
root -> controller -> sessionContext
在两种情况下,都使用和SessionContext
实例的相同实例,因为已解决了控制器请求范围的依赖关系。
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();
}
}
将中间件绑定到服务容器。
container.bind<ValidateSessionMiddleware>(ValidateSessionMiddleware).toSelf();
然后在控制器中注入它。
@injectable()
@controller("/")
class MyController {
@httpGet("/", ValidateSessionMiddleware)
public async index() {
}
}
如果发现将中间件注入是一件相当麻烦的事情,则可以保留现有设置,然后将SessionContext
服务放入工厂或提供者,以针对同一请求返回相同的会话上下文服务。
https://github.com/inversify/InversifyJS/blob/master/wiki/factory_injection.md