.NET Core 2.0非控制器类中使用IOptionsSnapshot的方法
嗨,这个问题我熟!在.NET Core 2.0里,非控制器类要获取IOptionsSnapshot<AppConfiguration>其实和控制器逻辑一致——核心是依赖注入,别想着直接new普通类,让DI容器帮你管理依赖就好。下面分两种常见场景给你详细说明:
1. 给普通类添加构造注入并注册到DI容器
首先,让你的TestClass通过构造函数接收IOptionsSnapshot<AppConfiguration>,就像控制器那样:
public class TestClass { private readonly AppConfiguration _appConfig; // 构造注入IOptionsSnapshot public TestClass(IOptionsSnapshot<AppConfiguration> options) { _appConfig = options.Value; } public void DoBusinessLogic() { // 直接使用配置项,比如: Console.WriteLine($"当前API地址:{_appConfig.ApiUrl}"); } }
然后,在Startup.cs的ConfigureServices方法里,把TestClass注册到DI容器中(根据你的业务需求选择生命周期:Transient/Scoped/Singleton):
public void ConfigureServices(IServiceCollection services) { // 你已有的配置绑定代码 services.Configure<AppConfiguration>(Configuration.GetSection("AppConfiguration")); // 注册普通类到DI容器,用Scoped和IOptionsSnapshot的生命周期匹配更合理 services.AddScoped<TestClass>(); // 其他服务注册(比如MVC等) services.AddMvc(); }
之后,当你需要使用TestClass时,不要直接new TestClass(),而是通过DI容器获取:比如在另一个服务的构造函数里注入TestClass,或者在控制器里注入它——和你用控制器获取配置的逻辑完全一样。
2. 在Startup流程中直接获取(比如Configure方法里)
如果是在Startup的流程中(比如Configure方法里,还没有控制器被调用)需要使用IOptionsSnapshot或者TestClass,你可以通过IServiceProvider来获取,但要注意IOptionsSnapshot是Scoped生命周期的,所以必须先创建一个临时作用域:
方式一:直接获取IOptionsSnapshot
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider) { // 创建临时作用域 using (var scope = serviceProvider.CreateScope()) { var options = scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<AppConfiguration>>(); var appConfig = options.Value; // 使用配置做初始化操作 Console.WriteLine($"初始化时读取到的API地址:{appConfig.ApiUrl}"); } // 其他中间件配置 app.UseMvc(); }
方式二:获取注册好的TestClass
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider) { using (var scope = serviceProvider.CreateScope()) { var testClass = scope.ServiceProvider.GetRequiredService<TestClass>(); testClass.DoBusinessLogic(); } app.UseMvc(); }
⚠️ 注意:尽量避免在ConfigureServices方法里直接获取IOptionsSnapshot,因为此时DI容器还没完全初始化,且没有默认作用域。如果一定要在ConfigureServices里用,需要手动构建临时服务提供者并创建作用域:
public void ConfigureServices(IServiceCollection services) { services.Configure<AppConfiguration>(Configuration.GetSection("AppConfiguration")); services.AddScoped<TestClass>(); // 仅在必要时使用这种方式 using (var tempProvider = services.BuildServiceProvider()) using (var scope = tempProvider.CreateScope()) { var testClass = scope.ServiceProvider.GetRequiredService<TestClass>(); testClass.DoBusinessLogic(); } }
最后提醒一句:优先用构造注入的方式,这是.NET Core依赖注入的最佳实践,代码更易测试、更符合开闭原则;服务定位器模式(直接从IServiceProvider获取)只作为特殊场景的补充。
内容的提问来源于stack exchange,提问作者Lukas Hieronimus Adler

