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

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 控制器开始的。

Olu*_*ule 6

当依赖被绑定时,只要它在“请求”中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)

同样validateSessionsessionContext在 , 在与控制器中的请求范围不同的请求范围中解析

// 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