javascript - InversifyJS - Inject service to express middleware - Stack Overflow

I am using inversify, inversify-binding-decorators, and inversify-express-utlis and have problem with e

I am using inversify, inversify-binding-decorators, and inversify-express-utlis and have problem with express middleware.

I am calling my middleware in this way:

let server = new InversifyExpressServer(container);
...
server.setConfig((app) => {

  app.use(validateSession);

});
...

This is my class for ioc registration. Please notice that here I manually register SessionContext in request scope

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 };

Now in my middleware I want to get my SessionContext in request scope service in this way:

 export async function validateSession(req: Request, res: Response, next: NextFunction) {

  try {
    ...

    let sessionContext = container.get<SessionContext>(TYPES.SessionContext);

    ...
    return next();
  }
  catch (err) {
   next(err);
  }
}

Service is resolved, but the problem is that if I resolve him in other place I am getting other instance. In request scope doesn't work when I use service inside express middleware. Always resolve gives new instance here. In other words - I want to start scope from express middleware. What I feel is that scope starts later from inversify-express-utils controller.

I am using inversify, inversify-binding-decorators, and inversify-express-utlis and have problem with express middleware.

I am calling my middleware in this way:

let server = new InversifyExpressServer(container);
...
server.setConfig((app) => {

  app.use(validateSession);

});
...

This is my class for ioc registration. Please notice that here I manually register SessionContext in request scope

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 };

Now in my middleware I want to get my SessionContext in request scope service in this way:

 export async function validateSession(req: Request, res: Response, next: NextFunction) {

  try {
    ...

    let sessionContext = container.get<SessionContext>(TYPES.SessionContext);

    ...
    return next();
  }
  catch (err) {
   next(err);
  }
}

Service is resolved, but the problem is that if I resolve him in other place I am getting other instance. In request scope doesn't work when I use service inside express middleware. Always resolve gives new instance here. In other words - I want to start scope from express middleware. What I feel is that scope starts later from inversify-express-utils controller.

Share Improve this question edited Aug 30, 2019 at 13:27 Nickolay 32.2k13 gold badges110 silver badges194 bronze badges asked Nov 26, 2018 at 10:44 templaristemplaris 2315 silver badges11 bronze badges 1
  • 1 I guess more people would be able to understand and have a chance to answer the question with an MCVE. For instance I haven't used inversify.js and to see what you mean I'd have to make one myself first, which is a too large time investment for me. – Nickolay Commented Aug 30, 2019 at 13:29
Add a ment  | 

1 Answer 1

Reset to default 7 +50

When dependency is bound inRequestScope, every call to container.get creates a singleton for as long as it's in a "request". https://github./inversify/InversifyJS/blob/master/wiki/scope.md#about-inrequestscope

For example,

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);

The above assert passes because when dependencies for line is resolved, they're retrieved in the same request scope. The dependency graph is one like:

root -> line (scope) -> coord (singleton)

In the same vein in validateSession, sessionContext is resolved in a separate request scope from that in the controller

// dependency graph in validateSession
root -> sessionContext

// dependency graph in controller
root -> controller -> sessionContext

I suggest to refactor the middleware from a server level middleware to a controller middleware. This way the dependency graph can be like:

// dependency graph in validateSession
root -> controller -> middleware -> sessionContext

// dependency graph in controller
root -> controller -> sessionContext

and the same instance of SessionContext instance is used in both cases since the dependency is resolved for the request scope of the controller.

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();
    }
}

Bind the middleware to the service container.

container.bind<ValidateSessionMiddleware>(ValidateSessionMiddleware).toSelf();

Then in the controller inject it.

@injectable()
@controller("/")
class MyController {

    @httpGet("/", ValidateSessionMiddleware)
    public async index() {
    }
}

If you find injecting the middleware to be a rather cumbersome business, you can keep the existing setup then make the SessionContext service into a factory or provider returning the same session context service for the same request.

https://github./inversify/InversifyJS/blob/master/wiki/factory_injection.md

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745279700a4620220.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信