【问题标题】:Constructor with non-DI and DI parameters具有非 DI 和 DI 参数的构造函数
【发布时间】:2018-04-04 10:25:52
【问题描述】:

我正在创建一个需要一些配置参数和记录器的服务。这是我的服务的构造函数:

public StorageProvider(string directory, ILogger<StorageProvider> logger)

我刚刚添加了记录器。我曾经在我的 startup.cs 中这样初始化它:

services.AddSingleton<IStorageProvider>(
    new StorageProvider(Configuration["TempStorage.Path"]));

directory 参数来自配置文件,并且记录器被 DI'ed。如何设置我的IStorageProvider

【问题讨论】:

  • 您是如何注册ILogger 的?这也是单例吗?如果是这样,将相同的实例传递给ILogger 注册到StorageProvider 构造。
  • 执行此操作时会包含记录器:WebHost.CreateDefaultBuilder(args)(请参阅docs.microsoft.com/en-us/aspnet/core/fundamentals/…
  • 你可以使用IOptions&lt;StorageProviderOptions&gt;注入目录路径。
  • 我不确定我是否完全理解你,但要明确一点:ILogger&lt;StorageProvider&gt; 不需要StorageProvider 的实际实例,如果你这么想的话。 type 参数用于区分日志条目,它实际上并没有任何事情。

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


【解决方案1】:

您应该执行以下操作:

  • 将配置值TempStorage:Path包装到自己的配置类中,例如StorageProviderSettings
  • StorageProvider 依赖于新的配置类。
  • 将该配置类作为单例注册到 ASP.NET 配置系统中。

例子:

public sealed class StorageProviderSettings
{
    public readonly string TempStoragePath;

    public StorageProviderSettings(string tempStoragePath)
    {
        if (string.IsNullOrWhiteSpace(tempStoragePath))
            throw new ArgumentException(nameof(tempStoragePath));
        this.TempStoragePath = tempStoragePath;
    }
}

public sealed class StorageProvider : IStorageProvider
{
    public StorageProvider(
        StorageProviderSettings settings, ILogger<StorageProvider> logger)
    {
        // ...
    }
}

// Registration
services.AddSingleton(new StorageProviderSettings(Configuration["TempStorage.Path"]));
services.AddSingleton<IStorageProvider, StorageProvider>();

【讨论】:

    【解决方案2】:

    使用 Tratcher 在评论中建议的 Options 模式。在official docs on Configuration 中阅读更多内容。

    基本上你定义一个类来保存你需要的值:

    public class StorageProviderOptions
    {
        public string TempStoragePath { get; set; }
    }
    

    然后在ConfigureServices注册类型:

    services.Configure<StorageProviderOptions>();
    

    在您的代码中,您请求 IOptions&lt;StorageProviderOptions&gt; 并将其设置为 StorageProviderOptions 的实例:

    public class SomeController
    {
        private readonly StorageProviderOptions _options;
    
        public SomeController(IOptions<StorageProviderOptions> options)
        {
            _options = options.Value;
        }
    }
    

    最后,确保您的配置源中有一个与TempStoragePath 名称匹配的元素。或者,您可以使用代码在ConfigureServices 中注册该选项:

    services.Configure<ServiceProviderOptions>(o => o.TempStoragePath = "temp");
    

    【讨论】:

    • 正如here 解释的那样,将IOptions&lt;T&gt; 注入应用程序组件是一个坏主意。
    • 有趣——我没读过。这样做之后,我倾向于同意那篇文章的评估(尽管目前 IOptions 仍然是记录在案的 MSFT 解决方案)。
    • 但众所周知,Microsoft 记录某些内容(甚至构建某些内容)这一事实并不能立即使其成为一个好的解决方案 :)
    • 确实如此。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-26
    • 2019-10-31
    • 1970-01-01
    • 2011-10-19
    • 2021-04-05
    • 1970-01-01
    相关资源
    最近更新 更多