8

ASP.NET Core - 配置系统之配置读取 - 啊晚

 1 year ago
source link: https://www.cnblogs.com/wewant/p/17110738.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一个应用要运行起来,往往需要读取很多的预设好的配置信息,根据约定好的信息或方式执行一定的行为。

配置的本质就是软件运行的参数,在一个软件实现中需要的参数非常多,如果我们以 Hard Code(硬编码)的方式写在应用代码中,这样配置就会很乱,而且后续也不容易修改。乱而多,而且不容易修改,这就需要一个统一管理的地方,最常见的方式就是配置文件,这个也是开发人员非常熟悉的方式。

通过配置文件设置好软件应用运行的各种参数之后,我们在开发过程中需要能够读取到配置文件的内容,根据配置内容进行软件逻辑的判断,实现完善的软件行为逻辑。这一篇就是介绍 .NET Core 框架下怎么使用配置系统,这也是 .NET Core 下的基础设施之一。

1. 配置读取

配置读取是配置系统最基本的操作,几乎是每个开发人员都会进行的操作,一个开发人员可能不清楚配置系统是怎么实现的,配置文件是怎么解析的,但一定都做过读取配置信息的操作。.NET Core 框架下对于配置系统的使用最终暴露出来的接口是 ·IConfiguration·,它是供配置数据的统一视图,配置读取就通过这个接口的实现来进行。

默认创建的 ASP .NET Core 框架模板项目中默认有一个 appsettings.json 配置文件,这个也是 ASP .NET Core 中最常用的配置文件,在配置文件中添加多一个 Settings 节点,内容如下:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Settings": {
    "key1": "value1",
    "key2": 1,
    "key3": true,
    "key4": {
      "subKey1": "value",
      "subKey2": 1
    },
    "items": [ "item1", "item2", "item3" ]
  }
}

我们要读取配置文件中的内容,例如读取“AllowedHosts”对于的值,只需要将其注入到需要的服务类中即可使用,ASP.NET Core 模板项目中使用Web主机构建和管理应用,在使用主机默认配置的时候已经将 Iconfiguration 服务注册到依赖注入容器之中。

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private readonly IConfiguration _configuration;
    public WeatherForecastController(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    [HttpGet]
    public Task Get()
    {
        var allowedHosts = _configuration["AllowedHosts"];
        Console.WriteLine(allowedHosts);
        // 配置键不区分大小写
        var allowedHosts = _configuration["AllowedHosts"];
        Console.WriteLine(allowedHosts);
        return Task.CompletedTask;
    }
}

上面这种读取方式是索引器方式,最简单也是基本的方式,配置被加载到内存中是以键值对的方式存在的,我们可以通过配置键读取配置值,键是字符串,不区分大小写,读取出来的值都是字符串。

配置文件中配置值往往不止一层,就像上面 appsettings.json 文件中,Logging 节点下还有子节点,如果需要这种分层数据,可以使用 : 字符(英文冒号)分隔层次结构,例如获取上面配置键 Default 对于的配置值。

// 以 : 作为分隔符,表示层级结构
var defalutLogLevel = _configuration["Logging:LogLevel:Default"];

如果配置值是数组,需要读取数组中具体的某一个值,可以用该值在数组中的索引作为key,例如读取上面配置文件中的items数组中的 item2。

// 读取数组,可以用值在数组中的索引作为key
var item2 = _configuration["Settings:items:1"];

这种方式读取配置有挺多不方便的地方,例如配置值是数值型的时候,需要我们直接转换,例如一次只能读取到一个配置值。微软通过 Microsoft.Extensions.Configuration.Binder 中的ConfigurationBinder 类提供了一些 IConfiguration 的静态方法,用于获取配置值时进行自动转换和绑定。

(1) GetValue

通过ConfigurationBinder中的GetValue扩展方法,一样可以通过配置键从配置系统中读取对于的配置值。该方法有多个重载,支持通过泛型的方式进行数据类型转换,并且支持设置默认值。

var defaultLogLevel2 = _configuration.GetValue<string>("Logging:LogLevel:Default");
// 配置信息中不包含 "Logging:LogLevel:Default" 这个Key时,以默认值 "Error" 返回
var defaultLogLevel3 = _configuration.GetValue<string>("Logging:LogLevel:Default", "Error");

(2) GetSection

这样子有些情况下仍然无法满足我们的需要,某一些情况下我们会需要直接读取配置中的一部分节点,例如直接读取上面配置中的 LogLevel 部分。IConfiguration 中的 GetSection 方法可以通过 Key 直接读取某一个子节点。该方法的返回值是 IConfigurationSection 类型,永远不会返回 null,IConfigurationSection 实际上是一个 IConfiguration 的派生接口,也就是说我们还可以从 IConfigurationSection 再去获取我们需要的具体的配置值。

var section = _configuration.GetSection("Settings:key4");
var defaultLogLevel4 = section["Default"];

(3) Get

上面讲到通过 GetSection 获取到了配置文件中的一部分子节点,但是那样仍然不方便,还是需要一个一个去读取具体的值。可以通过 ConfigurationBinder.Get 扩展方法,将配置以强类型的方式绑定到对象上。

首先需要定义一个类来接收配置文件中的节点信息

public class KeyOptions
{
    public string subKey1 { get; set
    public int subKey2 { get; set; }
}

然后通过以下方式进行绑定:

var keyOption1 = _configuration.GetSection("Settings:key4").Get<KeyOptions>();

(4) Bind

ConfigurationBinder.Bind 扩展方法与 Get 方法类似,也是用于将配置绑定为强类型对象,不过Bind的方法是绑定到一个已实例化的对象上,需要提供一个已存在的对象。

var keyOption2 = new KeyOptions();
_configuration.GetSection("Settings:key4").Bind(keyOption2);

(5) Exists

上面说过,GetSection 方法获取配置中的子节点,返回值永远不会为 null。如果我们传入了一个不存在的key,肯定是获取不到对于的值的,这种情况下还是需要判断对于的子节点到底是不是真正存在的,这时候可以使用 Exists 方法。

var section = _configuration.GetSection("settings");
var exist = section.Exists();

除此之外,还有一个 GetChildren 方法,无需参数,用于获取到当前配置节点的所有直接子节点的集合。

以上就是 .NET Core 体系下配置系统读取配置的基本介绍,涉及到的类型最主要的是 IConfiguration 接口,除此之外还有上面提到的 IConfigurationSection 接口,以及 IConfigurationRoot 接口。

IConfigurationRoot 表示配置的根节点,是IConfiguration的派生接口,以下为接口的定义:

public interface IConfigurationRoot: IConfiguration{
   // 存放了当前应用程序的所有配置提供程序
   IEnumerable<IConfigurationProvider> Providers { get; }
    // 强制从配置提供程序中重载配置
    void Reload();
}

这里可以看到一个关键的属性 IEnumerable Providers,这个就是配置系统中的配置信息的来源,后面会仔细讲这个。而 Reload 方法中最关键的也是调用集合中各个 IConfigurationProvider 进行数据加载。

IConfigurationSection 表示配置中的子节点,也是 IConfiguration 的派生接口,以下为接口的定义:

public interface IConfigurationSection: IConfiguration{
    // 该子节点在其父节点中所表示的 key,即直接对应的key
    string Key { get; }
    // 该子节点在配置中的全路径(从根节点开始,到当前节点以:符号分隔的路径)
    string Path { get; }
    // 该子节点的 value。如果该子节点是叶子节点,则Value为该节点对于的值,若其下存在子节点,则其始终为 null
    string Value { get; set; }
}

IConfigurationSection 接口通过以上三个属性,结合 IConfiguration中的 GetChildren 方法来完整地表示的一个子节点,而 Exists 方法判断节点是否为空,就是针对 IConfigurationSection 中的 Value 属性和 GetChildren 方法来进行的。

public static class ConfigurationExtensions{
    public static bool Exists(thisIConfigurationSection section){
        if(section == null)
        {
            returnfalse;
        }
        returnsection.Value != null || section.GetChildren().Any();
    }
}

参考文章:

ASP.NET Core 中的配置 | Microsoft Learn
配置 - .NET | Microsoft Learn
理解ASP.NET Core - 配置(Configuration)

ASP.NET Core 系列:
目录:ASP.NET Core 系列总结
上一篇:ASP.NET Core - 依赖注入(四)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK