InversifyJS-注入服务来表达中间件



我正在使用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

最新更新