tem*_*ris 4 javascript inversion-of-control inversifyjs
我正在使用 inversify、inversify-binding-decorators 和 inversify-express-utlis,并且在使用 express 中间件时遇到了问题。
我以这种方式调用我的中间件:
let server = new InversifyExpressServer(container);
...
server.setConfig((app) => {
app.use(validateSession);
});
...
Run Code Online (Sandbox Code Playgroud)
这是我的 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 };
Run Code Online (Sandbox Code Playgroud)
现在在我的中间件中,我想以这种方式在请求范围服务中获取我的 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);
}
}
Run Code Online (Sandbox Code Playgroud)
服务已解决,但问题是如果我在其他地方解决他,我会得到其他实例。当我在 express 中间件中使用服务时,在请求范围内不起作用。总是解决在这里给出新的实例。换句话说 - 我想从 express 中间件开始作用域。我觉得范围是从 inversify-express-utils 控制器开始的。
当依赖被绑定时,只要它在“请求”中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);
Run Code Online (Sandbox Code Playgroud)
上面的断言通过是因为当line解析依赖项时,它们在相同的请求范围内被检索。依赖图是这样的:
root -> line (scope) -> coord (singleton)
Run Code Online (Sandbox Code Playgroud)
同样validateSession,sessionContext在 , 在与控制器中的请求范围不同的请求范围中解析
// dependency graph in validateSession
root -> sessionContext
// dependency graph in controller
root -> controller -> sessionContext
Run Code Online (Sandbox Code Playgroud)
我建议将中间件从服务器级中间件重构为控制器中间件。这样依赖图可以是这样的:
// dependency graph in validateSession
root -> controller -> middleware -> sessionContext
// dependency graph in controller
root -> controller -> sessionContext
Run Code Online (Sandbox Code Playgroud)
并且SessionContext在这两种情况下都使用相同的实例实例,因为依赖是针对控制器的请求范围解析的。
root -> line (scope) -> coord (singleton)
Run Code Online (Sandbox Code Playgroud)
将中间件绑定到服务容器。
container.bind<ValidateSessionMiddleware>(ValidateSessionMiddleware).toSelf();
Run Code Online (Sandbox Code Playgroud)
然后在控制器中注入它。
// dependency graph in validateSession
root -> sessionContext
// dependency graph in controller
root -> controller -> sessionContext
Run Code Online (Sandbox Code Playgroud)
如果您发现注入中间件是一项相当麻烦的业务,您可以保留现有设置,然后将SessionContext服务转换为工厂或提供者,为相同的请求返回相同的会话上下文服务。
https://github.com/inversify/InversifyJS/blob/master/wiki/factory_injection.md