Deserialize options with configuration.Get<TOptions>
or configuration.Bind
call and register a POCO in DI container explicitly as 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: thanks to @NPNelson for .Get<TOptions>()
hint.
Then IOptions<T>
resolving is no longer needed, and the class dependencies become clear:
public HomeController(MyOptions options)
{
_options = options;
}
FYI: reading from an external service (database etc.) is also possible this way:
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>()));
}
Remarks:
- Singleton is not lazy (it's always instantiated at startup);
- In case of singleton registration, any ability to update options at runtime is lost (.NET Core natively supports runtime file reloading with
reloadOnChange
option setup: .AddJsonFile("appsettings.json", false, reloadOnChange: true)
);
If you really need the file reload and you still don't want to use IOptions
, consider a transient resolving. Of course, per-request resolving can lead to the significant perfomance decrease.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…