【问题标题】:Read and use settings from appsettings.json without IOptions<T>?在没有 IOptions<T> 的情况下从 appsettings.json 读取和使用设置?
【发布时间】:2017-09-26 12:58:19
【问题描述】:

.NET Core allows 懒惰地从配置文件中读取设置,将其反序列化为 POCO,并使用一行代码将该 POCO 注册到内置 DI 容器中:

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

然后任何消费者都可以解析 IOptions&lt;MyOptions&gt; 以访问该 POCO:

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

这种方法有明显的缺点:

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

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

在没有IOptions&lt;T&gt; 的情况下解决选项的最简单解决方案是什么?

【问题讨论】:

标签: c# dependency-injection asp.net-core .net-core


【解决方案1】:

使用 configuration.Get&lt;TOptions&gt;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;
}

UPD:感谢@NPNelson 提供.Get&lt;TOptions&gt;() 提示。

那么IOptions&lt;T&gt;就不再需要解析了,类依赖变得清晰了:

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

备注:

  • 单例不是惰性的(它总是在启动时实例化);
  • 在单例注册的情况下,任何在运行时更新选项的能力都会丢失(.NET Core 原生支持使用reloadOnChange 选项设置重新加载运行时文件:.AddJsonFile("appsettings.json", false, reloadOnChange: true));

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

【讨论】:

【解决方案2】:

如果你想对依赖它的服务进行单元测试,你可以模拟 IOptions。见this question and its answers。依赖于 IOptions 仍然只是依赖于一个接口,所以它不会(或不应该)使您的代码更难测试。

【讨论】:

  • 是的,当然。正如我所说,它只是更冗长。而且它仍然没有在构造函数中给出IOptions 的理由。
  • 而且,这不是问题的答案。
  • 很公平。 ?
猜你喜欢
  • 2018-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多