正如大家所知,在 .NET Core 中配置文件改成了 appsettings.json,表面上和 .NET Framework 的 web.config 或 app.config 好像没有太大的区别,只是一种是 json ,一种是 xml,但其实 .NET Core 的配置体系是一种全新的设计,灵活且具扩展性。这里主要介绍一下在 .NET Core 的配置体系下如何扩展自定义配置源,配置源其实就是配置信息存放的载体,最常用的就是文件类型。
.NET Core 配置体系
在进行自定义配置源介绍前,我们需要先了解一下 .NET Core 中的配置体系。 .NET Core 的配置体系中主要包含 ConfigurationProvider
、ConfigurationSource
、ConfigurationBuilder
、Configuration
几大核心对象。
ConfigurationProvider
实现 IConfigurationProvider
接口,配置源真正提供者,主要提供配置信息的加载与刷新。
ConfigurationSource
实现 IConfigurationSource
接口,提供对应的 ConfigurationProvider
具体实例。
ConfigurationBuilder
实现 IConfigurationBuilder
接口,负责将 ConfigurationSource
添加到配置源集合,再根据配置源集合构建出 ConfigurationRoot
对象,实现 IConfigurationRoot
接口。
Configuration
实现 IConfiguration
接口,Configuration
对象在逻辑上体现出树形化层次结构,配置信息均以键/值对的方式提供使用。
注 :IConfigurationRoot
、IConfigurationSection
均继承于 IConfiguration
,IConfigurationRoot
表示配置的根节点,IConfigurationSection
则表示配置的非根节点
所以他们之间的关系就是 ConfigurationProvider
实现配置提供,然后通过 ConfigurationSource
构造配置源实例,接着通过 ConfigurationBuilder
将配置源实例 ConfigurationSource
添加到配置源集合中并构造出 ConfigurationRoot
,最终以 Configuration
对象提供给程序使用。
默认情况下,Configuration
对象的 Providers
属性包含如下 Provider
:
-
ChainedConfigurationProvider
:应用程序本身相关配置信息,如:applicationName、contentRoot; -
JsonConfigurationProvider
:appsettings.json 和 appsettings.Development.json 中的配置信息; -
EnvironmentVariablesConfigurationProvider
:环境变量的配置信息; -
CommandLineConfigurationProvider
:命令行输入的配置信息;
这些类型的 Provider 在 .NET Core Web 项目中默认会自动加载,不需要手动配置,当然预置的 Provider 并不止这几种。
自定义配置源
前面提到 .NET Core 的配置体系是具有扩展性的,所以我们可以实现自定义的配置源,比如基于配置中心(如:etcd、apollo、consul 等)的实现,下面将模拟从配置中心获取,先了解整体实现方式,后面也会介绍我们在实际项目中基于 etcd 的实现方案。
创建 ConfigurationProvider
自定义 Provider 需要继承 ConfigurationProvider
,然后重写 Load
方法,设置 Data
属性。
public class CustomConfigurationProvider : ConfigurationProvider
{
public override void Load()
{
// 模拟从远程配置中心获取配置信息
using var httpClient = new HttpClient
{
BaseAddress = new Uri("http://localhost:5000")
};
var response = httpClient.GetStringAsync("/api/configs")
.ConfigureAwait(false)
.GetAwaiter()
.GetResult();
if (!string.IsNullOrEmpty(response))
{
Data = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
}
}
}
http://localhost:5000/api/configs 接口返回的 json 字符串,如下:
{"name":"beck","company":"mingdao"}
创建 ConfigurationSource
实现 IConfigurationSource
接口,在 Build
方法中返回 CustomConfigurationProvider
实例。
public class CustomConfigurationSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new CustomConfigurationProvider();
}
}
加入 ConfigurationBuilder 配置源列表
添加 IConfigurationBuilder
扩展方法 AddCustom
,将 CustomConfigurationSource
加入配置源集合中。
public static class CustomConfigurationExtensions
{
public static IConfigurationBuilder AddCustom(this IConfigurationBuilder builder)
{
return builder.Add(new CustomConfigurationSource());
}
}
启动入口添加 AddCustom
在 Program.cs
中的 ConfigureAppConfiguration
引用自定义配置源:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureAppConfiguration((context, configBuiler) =>
{
configBuiler.AddCustom();
});
webBuilder.UseStartup<Startup>();
});
测试效果
再次查看 Configuration
对象的 Providers
属性,发现已包含 CustomConfigurationProvider
:
然后可通过 Configuration
对象获取对应 key
的内容:
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { _configuration["name"], _configuration["company"] };
}
result
总结
以上完成了一个简单的自定义配置源,实际情况会比这复杂些。如果关注过 JsonConfigurationProvider
的配置加载参数,有一个 reloadOnChange
参数用来设置当配置文件有变化时是否重新加载,如果 reloadOnChange
设置为 true,当配置文件变化时不需要重启服务就可以生效,很多时候我们是需要 Provider 具有这个功能的,在接下来介绍的 EtcdConfigurationProvider
中会实现,实现源码 已在 Github 可供参考。
网友评论