我正在使用inversify、inversify绑定装饰器和inversify express utlis,并且express中间件有问题。
我用这种方式调用我的中间件:
let server = new InversifyExpressServer(container);
...
server.setConfig((app) => {
app.use(validateSession);
});
...
这是我在国际奥委会注册的班级。请注意,在这里,我在请求范围中手动注册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);
}
}
服务解决了,但问题是,如果我在其他地方解决了他,我就会得到其他实例。当我使用express中间件内部的服务时,请求范围内不起作用。始终解析在此处给出新实例。换句话说,我想从express中间件开始scope。我的感觉是,范围稍后从inversify express utils控制器开始。
当依赖关系绑定到inRequestScope
时,每次对container.get
的调用都会创建一个单例,只要它在"请求">中即可。https://github.com/inversify/InversifyJS/blob/master/wiki/scope.md#about-请求范围
例如,
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
并且在两种情况下都使用CCD_ 6实例的相同实例,因为对于控制器的请求范围解析了依赖性。
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