.NET 核心 allows从配置文件中延迟读取设置,将其反序列化为 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 作为单例:
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;
}
更新:感谢@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>()));
}
备注:
- Singleton 不是懒惰的(它总是在启动时实例化);
- 在单例注册的情况下,任何在运行时更新选项的能力都将丢失(.NET Core native 支持使用
reloadOnChange
选项设置重新加载运行时文件:.AddJsonFile("appsettings.json", false, reloadOnChange: true)
);
如果您真的需要重新加载文件但您仍然不想使用IOptions
,考虑 transient 解析。当然,按请求解析会导致性能显着下降。
关于c# - 在没有 IOptions<T> 的情况下读取和使用 appsettings.json 中的设置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43679665/