4

我正在使用 inversify、inversify-binding-decorators 和 inversify-express-utlis,但 express 中间件有问题。

我以这种方式调用我的中间件:

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

4

1 回答 1

6

当依赖被绑定时,只要它在“请求”inRequestScope中,每次调用都会创建一个单例。 https://github.com/inversify/InversifyJS/blob/master/wiki/scope.md#about-inrequestscopecontainer.get

例如,

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)

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

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

于 2019-08-31T09:07:45.990 回答