Configuration 配置框架

将代码中的配置信息抽取到文件中是良好的编程习惯,比如数据库的用户名、密码,我们如果切换数据库,直接修改配置文件即可,而无需修改源代码、重新编译工程。.Net Core提供了Microsoft.Extensions.Configuration配置框架及一系列针对各种类型配置文件格式(如JSON、XML等)的扩展包,我们可以借助这些工具很容易实现配置文件加载、配置重载等功能。

Configuration扩展包

Microsoft.Extensions.Configuration包含基本的配置框架接口,我们需要使用NuGet进行安装。Binder包提供了自动绑定配置数据到对象的功能,通常也需要安装。

Install-Package Microsoft.Extensions.Configuration
Install-Package Microsoft.Extensions.Configuration.Binder

除此之外,我们还需要根据具体使用的配置方式,安装对应的配置提供者包。比如我们希望读取JSON格式的配置文件,那么就可以安装微软官方提供的NuGet包。

Install-Package Microsoft.Extensions.Configuration.Json
Install-Package Microsoft.Extensions.Configuration.Xml
Install-Package Microsoft.Extensions.Configuration.Ini
Install-Package Microsoft.Extensions.Configuration.EnvironmentVariables
Install-Package Microsoft.Extensions.Configuration.CommandLine

微软官方提供了读取JSON、XML和INI格式配置文件的NuGet包,也提供了读取环境变量、命令行参数的包,此外还提供了读取自家Azure KeyVault的NuGet包。对于其它配置文件格式或是某种配置中间件,我们可以寻找其它第三方包或自己编写配置提供者。

配置框架基本使用

假设此时我们有如下JSON配置文件,我们打算使用配置框架读取其中的内容。

{
  "username": "tom",
  "password": "abc123",
  "proxy": {
    "host": "127.0.0.1",
    "port": 8080
  }
}

下面例子代码中,我们使用Configuration配置框架读取了上面的JSON文件,并取出其中的属性值。

using Microsoft.Extensions.Configuration;

namespace Gacfox.Demo.DemoNetCore
{
    class Program
    {
        static void Main()
        {
            ConfigurationBuilder builder = new ConfigurationBuilder();
            IConfigurationRoot root = builder
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("config.json")
                .Build();

            string username = root["username"];
            string proxyHost = root["proxy:host"];

            Console.WriteLine(username);
            Console.WriteLine(proxyHost);
        }
    }
}

代码中,我们首先创建了ConfigurationBuilder工具类,它是一个配置实例的构建器,随后我们通过它指定了配置文件的目录和文件名。另外这里值得注意的是我们的JSON数据是具有嵌套结构的,代码中我们使用了一种扁平化的语法读取了JSON数据中的属性。

AddJsonFile()方法另一个比较常用的重载用法如下:

IConfigurationRoot root = builder
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("config.json", optional: false, reloadOnChange: true)
    .Build();
  • optional:该配置文件是否是可选的,如果指定false则会在文件不存在时抛出异常
  • reloadOnChange:是否监测文件系统,在文件更新时自动重新加载配置

绑定配置信息到对象

在实际开发中,将配置的JSON、XML等数据绑定到对象是一个常见的做法,这样能够提升代码的抽象程度,使用也更为方便。将配置信息绑定到对象需要安装Microsoft.Extensions.Configuration.Binder包。

这里我们还是使用前面提供的JSON数据,首先我们需要创建两个绑定配置信息的实体类。

Config.cs

namespace Gacfox.Demo.DemoNetCore
{
    public class Config
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public Proxy Proxy { get; set; }
    }
}

Proxy.cs

namespace Gacfox.Demo.DemoNetCore
{
    public class Proxy
    {
        public string Host { get; set; }
        public int Port { get; set; }
    }
}

在读取配置的代码中,我们使用在IConfigurationRoot上调用Bind方法,即可将配置信息绑定到实体类上。

Program.cs

using Microsoft.Extensions.Configuration;

namespace Gacfox.Demo.DemoNetCore
{
    class Program
    {
        static void Main()
        {
            ConfigurationBuilder builder = new ConfigurationBuilder();
            IConfigurationRoot root = builder
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("config.json")
                .Build();

            Config obj = new Config();
            root.Bind(obj);

            Console.WriteLine(obj.Username);
            Console.WriteLine(obj.Proxy.Host);
        }
    }
}

结合DI使用Options注入配置信息

微软官方提供了Options包,它将配置框架和DI结合起来,提供了实际软件开发中访问配置信息的一种最佳实践,也是ASP.NET Core工程中默认使用的读取配置信息的方式,这里我们简单介绍一下。Options包也是以扩展形式提供的,我们需要使用NuGet进行安装。

Install-Package Microsoft.Extensions.Options

当然,除了Options包,我们还需要上面介绍的Configuration框架包,以及DI框架的包,这里就不多介绍了。

DemoService.cs

using Microsoft.Extensions.Options;

namespace Gacfox.Demo.DemoNetCore
{
    public class DemoService
    {
        private readonly IOptionsSnapshot<Config> configOptions;

        public DemoService(IOptionsSnapshot<Config> configOptions)
        {
            this.configOptions = configOptions;
        }

        public void Foo()
        {
            Config config = configOptions.Value;
            Console.WriteLine(config.Username);
        }
    }
}

在服务类代码中,我们使用构造函数注入了一个IOptionsSnapshot对象,它是对具体的配置对象的一层封装,这里增加一层封装很好理解,它用于实现配置信息的重新加载等功能,而具体使用时我们需要将配置对象从其中取出。

实际上,注入时除了IOptionsSnapshot,我们有3个选择:

  • IOptions:配置信息仅初始化1次,应用启动后修改配置文件不会自动更新
  • IOptionsSnapshot:应用启动后修改配置文件,超出Scope范围后会读取到更新的数据
  • IOptionsMonitor:应用启动后修改配置文件,能立即读取到更新的数据

实际开发中我们应该根据具体需求具体选择。

Program.cs

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace Gacfox.Demo.DemoNetCore
{
    class Program
    {
        static void Main()
        {
            ConfigurationBuilder builder = new ConfigurationBuilder();
            IConfigurationRoot root = builder
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("config.json", optional: false, reloadOnChange: true)
                .Build();

            ServiceCollection collection = new ServiceCollection();
            collection
                .AddOptions()
                .Configure<Config>(o => root.Bind(o));
            collection.AddTransient<DemoService>();

            using (ServiceProvider provider = collection.BuildServiceProvider())
            {
                DemoService demoService = provider.GetRequiredService<DemoService>();
                demoService.Foo();
            }
        }
    }
}

Program.cs中,我们首先初始化了配置框架,并指定了JSON文件等信息;然后我们初始化了DI框架,其中使用AddOptions()方法指定了读取配置的回调函数,这样配置信息才可以自动注入,紧接着又将DemoService加入IoC容器;最后,我们演示了从IoC容器中取出服务对象然后调用其中方法的过程。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap