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

时间:2018-11-26 10:44:53

标签: inversion-of-control inversifyjs

我正在使用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控制器开始。

1 个答案:

答案 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