比较几种注入配置的方法

时间:2019-02-26 19:22:27

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

我正在学习.net core提供的依赖注入。 到目前为止,我已经知道以下5种方法。

// 0
sc.AddSingleton(configuration);

//1
sc.Configure<ServiceOption>(_ => configuration.GetSection(nameof(ServiceOption)).Bind(_));

//2
sc.Configure<ServiceOption>(configuration.GetSection(nameof(ServiceOption)));

//3
sc.AddOptions<ServiceOption>()
.Bind(configuration.GetSection(nameof(ServiceOption)));

//4
sc.Configure<ServiceOption>(_ => _.ID = "from hard code");

问题

最后一个(#4)对我而言并不那么有趣,所以请忽略它。 我想知道,我们什么时候需要使用其余的每个?

这是源代码。

appsettings.json文件:

{
  "ServiceOption": {
    "ID": "from appsettings.json"
  }
}

代码:

interface IService
{
    void Do();
}

class Service : IService
{
    readonly ServiceOption option;
    readonly IConfigurationRoot configuration;

    public Service(IOptionsMonitor<ServiceOption> option)
    {
        this.option = option.CurrentValue;
    }

    public Service(IConfigurationRoot configuration)
    {
        this.configuration = configuration;
    }

    public void Do(){}
}

class ServiceOption
{
    public string ID { get; set; }
}



class Program
{
    private static readonly IConfigurationRoot configuration;

    static Program()
    {
        configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true)
            .Build();
    }

    static void Main()
    {
        using (ServiceProvider sp = RegisterServices())
        {
            sp.GetRequiredService<IService>().Do();
        }
    }

    static ServiceProvider RegisterServices()
    {
        ServiceCollection sc = new ServiceCollection();
        sc.AddTransient<IService, Service>();

        int selector = 0;

        switch (selector)
        {
            case 0:
                sc.AddSingleton(configuration);
                break;
            case 1:
                sc.Configure<ServiceOption>(_ => configuration.GetSection(nameof(ServiceOption)).Bind(_));
                break;
            case 2:
                sc.Configure<ServiceOption>(configuration.GetSection(nameof(ServiceOption)));
                break;
            case 3:
                sc.AddOptions<ServiceOption>()
                .Bind(configuration.GetSection(nameof(ServiceOption)));
                break;
            default:
                sc.Configure<ServiceOption>(_ => _.ID = "from hard code");
                break;
        }

        return sc.BuildServiceProvider();
    }
}

2 个答案:

答案 0 :(得分:2)

  1. sc.AddSingleton(configuration);

    这将注册该类的单个实例。当您不希望使用代码必须了解Microsoft.Extensions.Options时,这很有用。另一个常见的情况是您不打算使用“选项”模式提供的功能。

  2. sc.Configure<ServiceOption>(_ => configuration.GetSection(nameof(ServiceOption)).Bind(_));

    这使您可以使用功能配置选项。但是,由于您只是绑定到已经构建的Configuration,所以使用的语法很奇怪。

  3. sc.Configure<ServiceOption>(configuration.GetSection(nameof(ServiceOption)));

    与上面的操作相同,但是直接绑定到Configuration实例。

  4. sc.AddOptions<ServiceOption>().Bind(configuration.GetSection(nameof(ServiceOption)));

    这只是给您一个OptionBuilder<T>,您可以用它在一次流畅的通话中调用BindConfigurePostConfigure

答案 1 :(得分:1)

此答案是要添加排除的其他选项

//bind to an object graph using `ConfigurationBinder.Get<T>`
ServiceOption setting = configuration.GetSection(nameof(ServiceOption)).Get<ServiceOption>();
//adding that to the service collection as needed
sc.AddSingleton(setting);
  

ConfigurationBinder.Get<T>绑定并返回指定的类型。 Get<T>比使用Bind更方便。

在上面的选项中,可以将其显式注入到依赖项中

public Service(ServiceOption option) {
    this.option = option;
}

如果您不想将您的从属代码直接耦合到框架相关的关注点,则其推理类似于已经提供的答案。

引用Configuration in ASP.NET Core: Bind to an object graph

理想情况下,如果您不希望应用程序代码对框架抽象产生不必要的依赖,则不希望注入IConfigurationIOptions