ASP.NET Core ConfigureServices中嵌套依赖注入最佳实现方案咨询
针对你提到的需要在配置委托中获取服务、又不想提前构建ServiceProvider的场景,有三个通用的最佳实践可以覆盖绝大多数场景:
1. 使用IConfigureOptions<TOptions>实现延迟配置
所有ASP.NET Core中AddXXX方法接收的配置委托,本质上都是对对应选项类的配置(比如AddMvc的配置对应MvcOptions)。你可以将配置逻辑封装到IConfigureOptions<TOptions>的实现类中,该类支持通过构造函数注入任意你需要的服务,配置逻辑会在DI容器完全构建完成后自动执行。
示例代码:
// 定义MvcOptions的配置类 public class ConfigureMvcOptions : IConfigureOptions<MvcOptions> { private readonly ILogger _logger; // 直接通过构造函数注入需要的服务即可 public ConfigureMvcOptions(ILogger<ConfigureMvcOptions> logger) { _logger = logger; } public void Configure(MvcOptions options) { // 此处即可正常使用注入的服务完成配置 options.Filters.Add(new ApiExceptionFilter(_logger)); } }
在ConfigureServices中注册配置类即可:
// 注册配置实现 services.AddTransient<IConfigureOptions<MvcOptions>, ConfigureMvcOptions>(); // 原来的AddMvc无需再传入配置委托 services.AddMvc().AddFluentValidation();
该方案是最通用的实现,适用于所有基于选项系统的配置场景。
2. 优先使用框架提供的类型注册能力
针对过滤器、中间件、授权策略这类框架原生支持从DI解析的组件,优先使用按类型注册的API,不要手动new实例,框架会自动帮你解析所有构造函数依赖。
比如你提到的过滤器场景,直接使用如下注册方式即可:
setup.Filters.Add<ApiExceptionFilter>();
你只需要提前将ApiExceptionFilter注册到DI容器中,框架会在需要用到过滤器的时候自动构造实例,注入所有依赖。
3. 注册工厂委托实现延迟实例化
如果你需要自定义实例的构造逻辑,可以将构造逻辑封装成工厂委托注册到DI中,依赖的服务会在实例实际需要被创建时从容器中获取,不需要提前构建ServiceProvider。
示例代码:
// 注册ApiExceptionFilter的工厂逻辑 services.AddScoped<ApiExceptionFilter>(sp => { var logger = sp.GetRequiredService<ILogger>(); return new ApiExceptionFilter(logger); });
后续需要用到ApiExceptionFilter的地方直接注入该类型即可,DI会自动执行工厂逻辑构造实例。
注意:不要在
ConfigureServices中调用BuildServiceProvider是非常正确的做法,该操作会生成重复的容器实例,导致单例服务被多次初始化,引发很多难以排查的问题。以上所有方案的核心都是将依赖解析和实例构造的时机延迟到DI容器完全构建完成之后,避免提前构建容器。
内容的提问来源于stack exchange,提问作者yBother

