Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
368 views
in Technique[技术] by (71.8m points)

c# - Read and use settings from appsettings.json without IOptions<T>?

.NET Core allows to lazily read settings from configuration file, de-serialize it to a POCO and register that POCO in built-in DI container with one line of code:

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

Then any consumer can resolve IOptions<MyOptions> to access that POCO:

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

This approach has the significant disadvantages:

  • Unnecessary dependency from Microsoft.Extensions.Options package:

  • Mocking, testing and explicit instance creation become a bit more verbose.

What is the easiest solution to resolve options without IOptions<T>?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...