[英]Read and use settings from appsettings.json without IOptions<T>?
.NET Core 允许从配置文件中懒惰地读取设置,将其反序列化为POCO并使用一行代码在内置DI容器中注册该POCO:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MySection"));
}
然后任何消费者都可以解析IOptions<MyOptions>
来访问该POCO:
public HomeController(IOptions<MyOptions> optionsAccessor)
{
MyOptions options = optionsAccessor.Value;
}
这种方法有明显的缺点:
来自Microsoft.Extensions.Options
包的不必要的依赖:
模拟,测试和显式实例创建变得更加冗长。
在没有IOptions<T>
情况下解决选项最简单的解决方案是什么?
使用configuration.Get<TOptions>
或configuration.Bind
调用反序列化选项,并将DI容器中的POCO显式注册为singleton:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingletonFromFile<MyOptions>(Configuration.GetSection("MySection"));
}
//...
public static IServiceCollection AddSingletonFromFile<TOptions>(
this IServiceCollection services,
IConfiguration configuration)
where TOptions : class, new()
{
//POCO is created with actual values
TOptions options = configuration.Get<TOptions>();
services.AddSingleton(options);
return services;
}
UPD:感谢@NPNelson .Get<TOptions>()
提示。
然后不再需要IOptions<T>
解析,并且类依赖性变得清晰:
public HomeController(MyOptions options)
{
_options = options;
}
仅供参考:从外部服务(数据库等)读取也是可能的:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransientFromService<OptionsReader, MyOptions>(reader => reader.GetOptions());
}
//...
public static void AddTransientFromService<TReader, TOptions>(
this IServiceCollection services,
Func<TReader, TOptions> getOptions)
where TReader : class
where TOptions : class
{
services.AddTransient(provider => getOptions(provider.GetService<TReader>()));
}
备注:
reloadOnChange
选项设置重新加载运行时文件: .AddJsonFile("appsettings.json", false, reloadOnChange: true)
); 如果您确实需要重新加载文件并且仍然不想使用IOptions
,请考虑进行瞬态解析。 当然,按请求解决可能会导致显着的性能下降。
如果要对依赖于它的单元测试服务进行单元化,则可以模拟IOptions。 看到这个问题及其答案 。 取决于IOptions仍然只取决于接口,因此它不会(或不应该)使您的代码更难以测试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.