本文介绍了读取和使用 appsettings.json 中的设置而无需 IOptions<T>?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

.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"));
}

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

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:

  • 来自 Microsoft.Extensions.Options 包的不必要的依赖:

模拟、测试和显式实例创建变得更加冗长.

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

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

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

推荐答案

Deserialize options with configuration.Getconfiguration.Bind 调用并注册一个 POCODI 容器显式为单例:

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:感谢@NPNelson 的 .Get<TOptions>() 提示.

UPD: thanks to @NPNelson for .Get<TOptions>() hint.

那么IOptions就不再需要解析了,类的依赖就变得清晰了:

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>()));
}

备注:

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

如果您确实需要重新加载文件并且您仍然不想使用IOptions,请考虑暂时解析.当然,按请求解析会导致性能显着下降.

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.

这篇关于读取和使用 appsettings.json 中的设置而无需 IOptions&lt;T&gt;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-20 08:25