在没有IOptions 的情况下从appsettings.json读取和使用设置?

.NET Core 允许从配置文件中懒惰地读取设置,将其反序列化为POCO并使用一行代码在内置DI容器中注册该POCO:

public void ConfigureServices(IServiceCollection services) { services.Configure(Configuration.GetSection("MySection")); } 

然后任何消费者都可以解析IOptions来访问该POCO:

 public HomeController(IOptions optionsAccessor) { MyOptions options = optionsAccessor.Value; } 

这种方法有明显的缺点:

  • Microsoft.Extensions.Options包中不必要的依赖项:

  • 模拟,测试和显式实例创建变得更加冗长。

在没有IOptions情况下解决选项最简单的解决方案是什么?

使用configuration.Getconfiguration.Bind调用反序列化选项,并将DI容器中的POCO显式注册为singleton:

 public void ConfigureServices(IServiceCollection services) { services.AddSingletonFromFile(Configuration.GetSection("MySection")); } //... public static IServiceCollection AddSingletonFromFile( this IServiceCollection services, IConfiguration configuration) where TOptions : class, new() { //POCO is created with actual values TOptions options = configuration.Get(); services.AddSingleton(options); return services; } 

UPD:感谢@NPNelson .Get()提示。

然后不再需要IOptions解析,并且类依赖性变得清晰:

 public HomeController(MyOptions options) { _options = options; } 

仅供参考:从外部服务(数据库等)读取也是可能的:

 public void ConfigureServices(IServiceCollection services) { services.AddTransientFromService(reader => reader.GetOptions()); } //... public static void AddTransientFromService( this IServiceCollection services, Func getOptions) where TReader : class where TOptions : class { services.AddTransient(provider => getOptions(provider.GetService())); } 

备注:

  • Singleton不是懒惰的(它总是在启动时实例化);
  • 在单例注册的情况下,任何在运行时更新选项的能力都会丢失(.NET Core本身支持使用reloadOnChange选项设置重新加载运行时文件: .AddJsonFile("appsettings.json", false, reloadOnChange: true) );

如果您确实需要重新加载文件但仍然不想使用IOptions ,请考虑进行瞬态解析。 当然,按请求解决可能会导致显着的性能下降。

如果要对依赖于它的unit testing服务进行单元化,则可以模拟IOptions。 看到这个问题及其答案 。 取决于IOptions仍然只取决于接口,因此它不会(或不应该)使您的代码更难以测试。