使用Tsyringe依赖注入时控制器方法中service实例为undefined的问题
Tsyringe依赖注入中控制器方法内
this.userService为undefined的问题 我在使用Tsyringe结合Express控制器、服务与仓库实现依赖注入时遇到问题:服务与仓库的依赖注入正常工作,但控制器仅能在构造函数中访问注入的UserService,当通过Postman调用路由触发控制器的getUserById方法时,控制台输出serverInstance undefined并返回500错误。
控制器代码
import { Request, Response } from 'express' import { RequestResult } from '../../contracts/requestHandle/request-result' import {inject, injectable } from 'tsyringe' import { UserDto } from '../../contracts/transfer-objects/user-dto' import { UserLoginDto } from '../../contracts/transfer-objects/user-login-dto' import IUserService from '../../contracts/interfaces/services/user-service-interface' @injectable() export class UserController { constructor( @inject("UserService") private userService?: IUserService ){ this.userService!.getUserById('1').then((teste) => { console.log("teste", teste) }) } async getUserById(request: Request, response: Response<RequestResult<UserDto | null>>){ try{ console.log("serverInstance", this.userService) const entity = await this.userService!.getUserById(request.params.id) return response.status(200).json(entity) }catch(err){ const result = new RequestResult<any>(null, true, "Erro ao buscar o usuário") return response.status(500).json(result) } } }
服务代码
import { inject, injectable, Lifecycle, scoped } from "tsyringe" import { UserModel } from "../contracts/entities/user-model" import { UserDto } from "../contracts/transfer-objects/user-dto" import { sign } from "jsonwebtoken" import { RequestResult } from "../contracts/requestHandle/request-result" import automapper from "../contracts/utils/automapper" import type IUserRepository from "../contracts/interfaces/repositories/user-repository-interface" import IUserService from "../contracts/interfaces/services/user-service-interface" import { UserLoginDto } from "../contracts/transfer-objects/user-login-dto" import { RequestAnswer } from "../contracts/requestHandle/request-answer" @injectable() export class UserService implements IUserService { constructor( @inject("UserRepository") private userRepository: IUserRepository ){} async getUserById(userId: string) : Promise<RequestResult<UserDto | null>>{ console.log("getUserById", userId) const id = parseInt(userId) const userModel = await this.userRepository.getUserById(id) if(userModel){ const result = automapper.map("UserDto", UserDto, userModel) return new RequestResult<UserDto>(result) } else{ return new RequestResult<null>(null, false, "Usuário não encontrado.") } } }
仓库代码
import { context } from '../../repository/context/dbContext' import { UserModel } from '../../contracts/entities/user-model' import IUserRepository from '../../contracts/interfaces/repositories/user-repository-interface' export class UserRepository implements IUserRepository { async getUserById(userId: number) : Promise<UserModel | null> { console.log("getUserById", userId) const user = await context.user.findFirst({ where: { id: userId } }) return user } }
DI配置代码
import { container } from "tsyringe" import { UserService } from "../business/user-service" import { UserRepository } from "../repository/repositories/user-repository" import IUserRepository from "../contracts/interfaces/repositories/user-repository-interface" import IUserService from "../contracts/interfaces/services/user-service-interface" import { UserController } from "./controllers/user-controller" container .registerSingleton(UserController) .registerSingleton<IUserRepository>("UserRepository", UserRepository) .registerSingleton<IUserService>("UserService", UserService)
问题原因
构造函数中this.userService正常是因为实例化控制器时,this指向当前控制器实例;但通过Express路由调用方法时,方法的this上下文丢失了——Express会直接调用传入的方法回调,此时this不再指向控制器实例(严格模式下变为undefined)。
解决方案
有两种常用的修复方式:
1. 路由注册时绑定this上下文
在注册路由时,使用bind方法将控制器实例绑定到方法上,确保方法执行时this指向控制器实例:
import { container } from 'tsyringe'; import { UserController } from './controllers/user-controller'; import express from 'express'; const app = express(); const userController = container.resolve(UserController); // 绑定this到控制器实例 app.get('/users/:id', userController.getUserById.bind(userController));
2. 使用箭头函数定义控制器方法
箭头函数不会创建自己的this,会继承构造函数中的this上下文,修改控制器方法定义为箭头函数:
@injectable() export class UserController { constructor( @inject("UserService") private userService?: IUserService ){ this.userService!.getUserById('1').then((teste) => { console.log("teste", teste) }) } // 改为箭头函数 getUserById = async (request: Request, response: Response<RequestResult<UserDto | null>>) => { try{ console.log("serverInstance", this.userService) const entity = await this.userService!.getUserById(request.params.id) return response.status(200).json(entity) }catch(err){ const result = new RequestResult<any>(null, true, "Erro ao buscar o usuário") return response.status(500).json(result) } } }
两种方式都能解决this.userService为undefined的问题,可根据项目习惯选择。
内容的提问来源于stack exchange,提问作者Eduardo Angelim
相关产品推荐
相关产品推荐

