将依赖注入(DI)常用类整合到单个类中是否可行?
依赖注入场景下的代码复用方案分析
你的方案确实能有效减少重复代码,核心优势很明显:
- 原本每个控制器(包括基控制器)的构造函数都要逐一罗列5个依赖参数,现在只需要注入
BaseApiDIContainer这一个参数即可,不管是基类还是子类控制器,构造函数的代码量都能大幅缩减,彻底避免了重复写依赖列表的问题。
不过你的示例代码还能进一步简化:基控制器里不需要重新定义_userManager这类字段,直接把BaseApiDIContainer作为受保护字段,子类直接通过它访问服务即可,连基类里的赋值代码都能省掉,比如:
public class ApBaseApiController : ApiController { protected readonly BaseApiDIContainer _container; public ApBaseApiController(BaseApiDIContainer container) { _container = container ?? throw new ArgumentNullException(nameof(container)); } } public class AccountController(BaseApiDIContainer container) : ApBaseApiController(container) { public async Task<ApplicationUser> DoSomethingWithUser(string currentUserId) { return await _container.UserManager.FindByIdAsync(currentUserId); } }
你提到的生命周期统一限制是这个方案的核心问题,这里需要注意:
- 比如
MembershipDbContext和IHttpContextAccessor通常是Scoped生命周期,如果你把BaseApiDIContainer注册为Transient,会导致这些Scoped服务被提前释放,引发运行时错误。 - 解决思路很直接:将
BaseApiDIContainer的生命周期注册为和内部最长生命周期的服务一致。如果内部包含Scoped服务,就注册为Scoped:
Scoped容器可以兼容Transient、Scoped甚至Singleton服务的注入,不会出现生命周期不匹配的问题。builder.Services.AddScoped<BaseApiDIContainer>();
另外注意你示例代码里的两处bug:
EmailService的空检查错误使用了nameof(userManager),应该改为nameof(emailService);Db的空检查错误使用了nameof(MembershipDbContext),应该改为nameof(db)。
内容的提问来源于stack exchange,提问作者Nick1991
相关产品推荐
相关产品推荐

