【问题标题】:Reading appsettings.json directly, or accessing IOptions<T> from an Extension method直接读取 appsettings.json,或从扩展方法访问 IOptions<T>
【发布时间】:2018-07-30 18:26:40
【问题描述】:

我有一个扩展方法,用于从当前ClaimsPrincipal 中读取特定声明。但我还需要对照appsettings.json 中的项目列表检查此值。 我通过使用ConfigurationBuilder() 直接以与启动相同的方式读取appsettings 来完成这项工作,尽管不是使用

.SetBasePath(Directory.GetCurrentDirectory())

正如我在启动时所做的那样,我正在使用

.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location))

虽然不漂亮,但效果很好。 但是,当运行单元测试时,以下任何一项都无法让我了解 appsettings 所在的位置

Directory.GetCurrentDirectory()
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)

而且我看不到将IHostingEnvironment 或类似的东西放入扩展方法中以读出appsettings 的方法,或者确实放弃ConfigurationBuilder() 并在扩展方法中获取IOptions,在这样单元测试和运行代码才能正常工作。

我认为一定有办法做到这一点?虽然我希望我根本不应该尝试并将对项目列表的检查完全提升到另一个类......

【问题讨论】:

  • 似乎您正在使用扩展方法与 DI 作斗争。是否有任何原因不能将配置作为参数传递给扩展方法?
  • 说实话,我认为这可能是最简单的选择

标签: unit-testing asp.net-core dependency-injection .net-core


【解决方案1】:

不建议将可能需要依赖项的业务逻辑放入静态方法中。这使得向它们注入依赖项变得困难。选项很少:

  1. 将静态方法重新设计为服务,以便可以通过构造函数注入依赖项。 (推荐)

public class Foo : IFoo
{
    private readonly IOptions<FooOptions> optionsAccessor;
    public Foo(IOptions<FooOptions> optionsAccessor)
    {
        this.optionsAccessor = optionsAccessor ??
            throw new ArgumentNullException(nameof(optionsAccessor));
    }

    public void DoSomething()
    {
         var x = this.optionsAccessor;

         // Same implementation as your static method
    }
}
  1. 将依赖项作为扩展方法的参数注入。

public static void DoSomething(this object o, IOptions<FooOptions> optionsAccessor)
{
    // Implementation
}
  1. 将静态方法重新设计为抽象工厂 like this example 的外观。

【讨论】:

  • 谢谢,我希望不必重做这个,因为它只是我们负载平衡环境的一个特殊实现,但我想没有逃脱的余地。感谢您的帮助
猜你喜欢
  • 2019-02-14
  • 2017-09-26
  • 2010-12-13
  • 1970-01-01
  • 2019-01-24
  • 1970-01-01
  • 2023-03-16
  • 2011-11-06
  • 2020-01-23
相关资源
最近更新 更多