更新记录
转载请注明出处:
2022年10月31日 发布。
2022年10月28日 从笔记迁移到博客。
ASP.NET Core应用配置
说明
当我们需要将程序发布到不同环境中时,需要让应用支持配置,以在运行时执行不同的逻辑,例如连接不同环境的数据库、日志的级别开关等。本质上,配置是一种运行时对应用程序行为进行控制的手段。ASP.NET Core通过提供全新的配置组件来提供配置的读取能力,既支持将环境变量、命令行参数、内存字典作为配置数据源,也支持以多种文件格式作为配置数据源,同时提供了轻量级的扩展接口,我们可以非常轻松地定义自己的配置数据源。
ASP.NET Core
中的配置与ASP.NET
项目中的配置有很大不同,ASP.NET
项目使用web.config
文件,ASP.NET Core
项目使用多种配置源对项目进行配置。ASP.NET Core
配置系统支持丰富的配置源,包括文件(json、xml、ini等)、注册表、环境变量、命令行、Azure Key Vault等,还可以配置自定义配置源。可以跟踪配置的改变,可以按照优先级覆盖。
配置组件的核心能力是从各种数据源读取并格式化为Key-Value(键-值)结构。
配置组件的构造过程
配置组件的核心部分包含在下面两个组件包中,与依赖注入组件的模式一样,都是接口实现分离的模式:
Microsoft.Extensions.Configuration.Abstractions
Microsoft.Extensions.Configuration
其中核心的类型接口有:
IConfigurationBuilder,表示配置对象构造者,负责IConfigurationRoot的构造。
IConfigurationSource,表示一个配置数据源。
IConfigurationProvider,表示配置提供程序,负责从数据源读取配置数据并转换为Key-Value结构。
IConfiguration,表示配置对象,抽象为一个Key-Value结构。
IConfigurationRoot,表示配置对象的根,继承自IConfiguration。
IConfigurationSection,表示配置对象的一个节点,继承自IConfiguration。
整个配置组件构建过程:
创建IConfigurationBuilder。
向Builder中添加各种配置源(ConfigurationSource)。
通过Build方法构建IConfigurationRoot对象,其内部过程如下:
由ConfigurationSource的Build方法创建对应的ConfigurationProvider。
将ConfigurationProvider存储在ConfigurationRoot中。
ASP.NET Core主要的配置文件
配置文件 | 描述 |
---|---|
Panda.csproj | 描述项目信息,比如依赖关系和构建说明 |
global.json | 定义.NET Core SDK版本 |
launchSettings.json | 应用启动配置 |
appsettings.json | 应用的环境配置 |
secrets.json | 用户秘密 |
Program.cs | 应用启动文件 |
Startup.cs | 应用服务和中间件配置 |
ASP.NET Core配置源的默认顺序
配置文件内部视角
配置文件外部视角
提示:优先级从低到高。
Program.cs文件
Program.cs文件中定义了Program类型,是应用程序的入口(entry point for app)。通常在该文件中配置应用的“托管”环境(configure the “hosting” environment)。
Porgram类型定义如下:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
在Main方法中,调用了CreateDefaultBuilder(args)方法
CreateDefaultBuilder用于设置项目的默认配置
调用Host.CreateDefaultBuilder(args)方法中创建了应用的默认的配置构建器
然后调用配置构建器的ConfigureWebHostDefaults方法创建默认的配置
最后调用UseStartup<Startup>
()方法来实例化Startup类
Program.cs在ASP.NET Core程序中的位置
CreateDefaultBuilder方法使用默认的构建器模式创建一个Web主机
该主机可以指定诸如要使用的Web服务器和配置源之类的东西
以及选择用于完成应用程序服务配置的类
默认情况下使用的Startup类作为服务配置类
Startup.cs文件
Startup.cs文件中定义了Startup类
在Startup类中可以配置应用程序所需的嵌入式或自定义服务
Startup类默认的定义如下:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime.
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Startup类构成:一个构造函数+2个方法+1个属性
属性
用于保存配置项的引用
构造函数
用于注入默认的配置项到配置项属性中
ConfigureServices方法
正如方法名描述的用于配置服务
ConfigureServices方法注意:
由于大型应用程序可能包含许多不同的服务
因此ConfigureServices方法中可能会出现很多混乱且无法读取的代码
为了使下一个人和我们自己更具可读性
我们可以将代码结构化为逻辑块,
然后将这些块分成扩展方法
然后在ConfigureServices方法中引用扩展方法
Configure方法
用于向应用程序的请求管道中添加中间件组件
MemoryConfigurationSource(内存配置提供程序)
说明
配置组件内置了内存配置提供程序,可以定义一个键-值对集合作为配置数据源。通常情况下可以使用字典类Dictionary<string, string>来处理。
内存配置提供程序的配置实例:
IConfigurationBuilder builder = new ConfigurationBuilder();
var configData = new Dictionary<string, string>() {
{ "key1 ","v1"},
{ "section1:aaa","v2"}
};
//方法一
builder.Add(new MemoryConfigurationSource { InitialData = configData });
//方法二
builder.AddInMemoryCollection(configData);
IConfigurationRoot root = builder.Build();
上面两种方法是等价的,一种直接构造内存配置数据源,另一种使用了扩展方法。扩展方法被广泛使用,建议在实际项目中使用。
通常情况下,内存配置为程序提供了与环境无关的特定行为的配置,这在定义应用程序时非常有用。明确定义组件使用的配置值,可以避免组件采用隐含的默认配置,使得应用程序的行为更为明确,代码也更易管理。
实例
var builder = WebApplication.CreateBuilder(args);
//定义内存配置项
var mySettings = new Dictionary<string, string> { };
mySettings.Add("Title", "这是标题");
mySettings.Add("Content", "这是内容");
//直接引入加载的内存配置项
builder.Configuration.AddInMemoryCollection(mySettings);
在控制器中使用
//注入配置服务
[HttpGet("ConfigTest")]
public string ConfigTest([FromServices] IConfiguration configuration)
{
//获得配置文件中的具体值
return configuration["Title"];
}
Command-Line Arguments(命令行配置提供程序)
说明
命令行配置提供程序可以轻松地将命令行参数作为配置的数据源。要使用命令行配置提供程序,需要安装NuGet包。
默认情况下,ASP.NET Core内置了命令行配置提供程序,无需再安装。
Microsoft.Extensions.Configuration.CommandLine
并使用如下代码将其注册到IConfigurationBuilder中。
static void Main(string[] args)
{
IConfigurationBuilder builder = new ConfigurationBuilder();
//将Main函数接收到的命令行参数args传递给提供程序,这样就可以在配置中读取应用程序启动命令传递进来的参数。
builder.AddCommandLine(args); //添加命令行配置提供程序
IConfigurationRoot root = builder.Build();
}
使用
基本使用
命令行参数需要遵循如下规则:
-
Key和Value之间可以用等号“=”连接。
-
Key和Value之间使用空格隔开时,Key必须使用“--”或者单斜杠“/”作为前缀。
直接在dotnet CLI命令中加入参数即可
dotnet run PandaKey="PandaValue"
dotnet run CommandLineKey1=value1 CommandLineKey2=value2 CommandLineKey3=value3
dotnet run --CommandLineKey1=value1 --CommandLineKey2=value2 --CommandLineKey3=value3
dotnet run /CommandLineKey1=value1 /CommandLineKey2=value2 /CommandLineKey3=value3
注意:
命令行参数支持不带前置符号。
或使用“--”和“/”作为参数的前置符号。
每个参数由参数名、等号和参数值组成。
参数别名
为了使程序支持简写和全写的命令行参数,可以在自己写个参数列表。然后使用AddCommandLine方法的第二个参数进行自动映射。
static void Main(string[] args)
{
IConfigurationBuilder builder = new ConfigurationBuilder();
//自己写个参数列表
var switchMappings = new Dictionary<string, string>
{
{ "-k1","key1"},
{ "--k1-full","key1"},
{ "-k2","key2"},
{ "--k2-full","key2"}
};
builder.AddCommandLine(args, switchMappings);
IConfigurationRoot root = builder.Build();
var key2 = root["key2"];
}
使用方法
dotnet run key2=abc
dotnet run --key2 abc
dotnet run -k2 abc
dotnet run --k3 abc
Environment Variables(环境变量配置提供程序)
环境变量配置说明
在容器化流行的当下,尤其是Kubernetes中,环境变量被广泛使用,这得益于容器的环境隔离能力,使得应用程序运行环境相互独立。使用环境变量作为配置数据源是一个不错的做法。环境变量配置提供程序提供了从环境变量读取配置的能力,因此可以非常轻松地适配容器化环境。
环境变量配置提供程序由包Microsoft.Extensions.Configuration.EnvironmentVariables
提供,其核心能力可以概括为:
- 支持仅加载特定前缀的环境变量,在加载时前缀会从Key中去除。
- 对于不支持“:”的系统,可以使用双下划线“”表示配置段的分层键。
- 双下划线“”在加载后会被替换为“:”。
ASP.NET Core中的环境变量
一般情况下ASP.NET Core环境变量分为:
环境类型 | 环境说明 |
---|---|
Development | 开发环境 |
Staging | 演示(临时、演示)环境 |
Production | 生产环境 |
也可以自定义环境变量
比如:Testing 对应测试环境
设置环境变量
编辑launchSettings.json文件设置环境变量
打开launchSettings.json文件,在environmentVariables节点下添加键值对即可。
使用Visual Studio GUI编辑环境变量
通过系统设置编辑环境变量
直接编辑即可
ASPNETCORE_ENVIRONMENT环境变量原理
ASP.NET Core提供了开箱即用的IWebHostEnvironment服务。使用该服务,可以访问ASPNETCORE_ENVIRONMENT环境变量值。在Configure方法中,默认已经注入该服务了,可以直接使用。可以用于检测当前所在环境、当前环境的名称。
实例:获得当前环境的名称
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Run(async (content) =>
{
//输出环境变量名称值
await content.Response.WriteAsync(env.EnvironmentName);
});
}
实例:检测当前所在环境
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//检测是否开发环境
if (env.IsDevelopment())
{
app.Run(async (content) => {
await content.Response.WriteAsync("IsDevelopment");
});
}
//检测是否演示环境
if(env.IsStaging())
{
app.Run(async (content) => {
await content.Response.WriteAsync("IsStaging");
});
}
//检测是否生产环境
if (env.IsProduction())
{
app.Run(async (content) => {
await content.Response.WriteAsync("IsProduction");
});
}
//检测是否自定义的环境
if(env.IsEnvironment("Testing"))
{
app.Run(async (content) => {
await content.Response.WriteAsync("Testing");
});
}
}
使用环境变量
在命令行中定义环境变量
set Key1="Value1"
set Section1__Key1=Value11
set MyEnv_Key1="MyEnv Value1"
set MyEnv_Section1__Key1="MyEnv Value11"
dotnet run
在代码中使用
IConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddEnvironmentVariables("MyEnv_"); //加载MyEnv_前缀的配置
IConfigurationRoot root = builder.Build();
Console.WriteLine($"Key1:{ root["Key1"]}");
Console.WriteLine($"Section1:Key1:{ root ["Section1:Key1"]}");
Console.WriteLine($"Key1 in Section1:{ root.GetSection("Section1")["Key1"]}");
Console.WriteLine($"MyEnv_Key1:{ root["MyEnv_Key1"]}");
Console.WriteLine($"MyEnv_Section1:Key1:{ root["MyEnv_Section1:Key1"]}");
launchSettings.json(启动配置)
配置文件说明
launchSettings.json 正如其文件名称是一个启动配置文件,位于项目的Properties目录下。用于配置ASP.NET Core应用程序的启动相关的参数,比如包含用于启动IIS和自托管应用程序(Kestrel)设置的配置。Visual Studio和.NET CLI在启动项目的时候,会读取该文件的配置信息。可以使用Visual Studio的GUI方式配置该文件,也可以直接编辑JSON代码。
注意:
-
launchSettings.json文件仅用于本地开发环境,发布时无需带上该文件。
-
如果需要在部署生产环境时使用配置信息,应存储在appsettings.json文件夹中。
-
appsettings文件还可以配置不同环境,比如appsettings.Development.json。
除了appsettings.json文件,还可以采用其他方式配置程序,比如:环境变量、User Secrets、命令行、自定义参数。
默认项目模板设置的配置项如下:
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:18608",
"sslPort": 44326
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": false,
"launchUrl": "weatherforecast",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"WebApplication6": {
"commandName": "Project",
"launchBrowser": false,
"launchUrl": "weatherforecast",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
其中的具体配置项说明
launchBrowser 配置项目启动后是否启动浏览器
applicationUrl 配置应用启动的地址
launchUrl 配置项目启动后打开的URL的参数
需要配置launchBrowser为true才生效
sslPort 配置HTTPS/SSL的端口
environmentVariables 配置项目的环境变量
iisSettings 配置IIS/IIS Express的配置项
iisExpress 配置只针对IIS Express的配置项
windowsAuthentication 配置IIS是否启用Windows认证
anonymousAuthentication 配置IIS是否启用匿名认证
从配置信息中,可以看到有2个配置信息:IIS Express和 具体项目名称。当在Visual Studio 2022中按F5时,默认调用的是具体项目名称的配置信息。当在Visual Studio 2019中按F5时,默认调用的是IIS Express的配置信息。当然,也可以自己通过Visual Studio中的调试按钮右侧的小箭头进行调整。
当使用.NET CLI命令行启动项目的时候,默认使用具体项目名称的配置文件。
通过Visual Studio GUI方式配置launchSettings.json
打开Visual Studio,点击Properties目录,会自动弹出GUI配置界面。打开项目属性界面,切换到“调试”栏。
环境变量中的Development,可以换为:Staging、Production。通过切换环境变量,可以在Startup.cs文件中,通过环境变量配置其他配置。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
//只在开发环境才生效
app.UseDeveloperExceptionPage();
}
}
launchSettings.json与appsettings.json的区别
-
都是配置文件,但ASP.NET Core应用读取的先后不同。
-
当我们发出dotnet run命令时将加载launchSettings.json文件。
-
launchSettings.json用于开发环境,appsettings.json用于部署环境。
-
appsettings.json在CreateDefaultBuilder方法中使用。
CreateDefaultBuilder方法许多配置源示意图,读取顺序与优先级正好相反。
读取配置项的值
直接注入configuration服务,然后调用即可。
public string Test([FromServices] IConfiguration configuration)
{
string value = configuration["ASPNETCORE_ENVIRONMENT"];
Console.WriteLine(value);
return "";
}
launchSettings.json文件 与 项目配置托管模型 的关联
当使用launchSettings.json文件中的不同配置项 和 项目AspNetCoreHostingModel
设置为不同值,会影响启动的服务器类型
CommandName launchSettings配置 | AspNetCoreHostingModel 托管模型 | Internal Web Server 内部服务器 | Extenal Web Server 外部服务器 |
---|---|---|---|
具体项目名称 | 忽略托管模型值 | 只使用IIS Express | 只使用IIS Express |
IIS Express | InProcess | 只使用IIS Express | 只使用IIS Express |
IIS Express | OutOfProcess | Kestrel | IIS Express |
IIS | InProcess | 只使用IIS | 只使用IIS |
IIS | OutOfProcess | Kestrel | IIS |
appsettings.json(应用配置)
配置文件说明
appsettings.json根据不同的环境进行设置只有在指定环境下才启用的配置。
apsettings.{EnvironmentSuffix}.json会覆盖appsettings.json的配置,即具体的环境的配置信息优先。
比如可以自定义:
appsettings.Development.json 用于开发环境
appsettings.Test.json 用于测试环境
appsettings.Production.json 用于部署环境
appsetitng文件根据设置的ASPNETCORE_ENVIRONMENT环境变量来进行启用对应设置
比如在不同的操作系统下设置好环境变量后,会触发不同的环境配置
in Windows
set ASPNETCORE_ENVIRONMENT=Production
in Linux
export ASPNET_CORE_ENVIRONMENT=Production
默认项目模板的appsettings.json内容
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
写入配置信息到appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"PandaKey": "PandaValue" //自定义的配置项
}
读取appsettings.json等配置文件中的配置信息
在需要读取配置项的地方,注入IConfiguration服务,然后直接读取即可
实例:在控制器中使用
using Microsoft.AspNetCore.Mvc;
//引入命名空间
using Microsoft.Extensions.Configuration;
namespace WebApplication2.Controllers
{
public class PandaController : Controller
{
public IConfiguration Configuration { get; set; }
//在控制器或者方法中注入配置服务
public string Index([FromServices] IConfiguration configuration)
{
this.Configuration = configuration;
//读取配置项
return Configuration["PandaKey"];
}
}
}
读取多层级的配置项,可以使用冒号:分隔。比如:
//appsetting.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
//加入自定义配置项
"Config1": {
"SubConfig1": "666"
}
}
public string Test([FromServices] IConfiguration configuration)
{
//直接访问配置项的值
string configValue = configuration["Config1:SubConfig1"];
Console.WriteLine(configValue ?? "NoValue");
return "";
}
当配置参数很多的时候一个一个去取参数就很麻烦,这时候配置参数绑定到具体的配置对象的需求就产生了,只需要使用Get方法即可。
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
//自定义的配置项
"SubConfig1": "666",
"SubConfig2": "888",
"SubConfig3": "999"
}
//自定义配置对象
namespace PandaTest.Configuration
{
public class PandaConfig
{
public string SubConfig1 { get; set; }
public string SubConfig2 { get; set; }
public string SubConfig3 { get; set; }
}
}
//在控制器中使用
public string Test([FromServices] IConfiguration configuration)
{
//绑定到自定义的配置对象
PandaConfig pandaConfig = configuration.Get<PandaConfig>();
Console.WriteLine(pandaConfig.SubConfig1);
Console.WriteLine(pandaConfig.SubConfig2);
Console.WriteLine(pandaConfig.SubConfig3);
return "";
}
User Secrets(用户机密)
secrets.json配置文件说明
在开发过程中,有些信息是机密信息,比如加密密钥,比如:第三方密钥,微信、支付宝、微博密钥。多人进行协同开发中,每个人本地数据库设置的账号和密码也不同。所以将这部分比较机密的配置信息单独放在文件中保存,这就是secrets.json文件。
配置文件secrets.json在ASP.NET Core应用中的位置。
Visual Studio GUI方式配置secrets.json
选中【项目】,鼠标右键点击【管理用户机密】。
Visual Studio会自动创建一个secrets.json文件,我们可以在里面添加键值对,然后保存文件。
Visual Studio会自动在项目配置文件添加
该节点中的GUID和secrets.js文件中的GUID是对应的。
secrets.js文件默认存放在
Windows: %APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json
Linux/OSX: ~/.microsoft/usersecrets/<user_secrets_id>/secrets.json
注意:内容都是明文的。
还可以直接使用Visual Studio打开secrets.js文件所在的目录位置。
使用dotnet命令行配置secrets.json
使用dotnet user-secrets可以执行用户机密文件的操作。
首先,在项目根目录下执行初始化user secret
dotnet user-secrets init
注意:如果没有该命令,可以安装该工具包。
dotnet tool install --global user-secrets
本质是在项目配置文件.csproj文件中加入UseSecretsId节点。并生成对应的机密文件。
<PropertyGroup>
<UserSecretsId>8C93C1B2-ABC4-41CB-A81E-EB2A3D675330</UserSecretsId>
</PropertyGroup>
注意:这里的GUID叫做user_secrets_id。
然后 在项目的根目录下执行命令来增加机密配置项:
dotnet user-secrets set “Key” “Value”
比如:将UserID的键值对存储在secrets.json中
dotnet user-secrets set “UserID” “sa”
比如:将Password的键值对存储在secrets.json中
dotnet user-secrets set “Password” “Password”
如果需要存储层级数据可以使用冒号:分隔即可。
dotnet user-secrets set “Key:SubKey” “Value”
具体文件保存在
Windows: %APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json
Linux/OSX: ~/.microsoft/usersecrets/<user_secrets_id>/secrets.json
Windows中的secrets.json文件具体位置:
更多的命令操作可以使用--help命令参数查看。
dotnet user-secrets --help
支持的操作:
clear Deletes all the application secrets
init Set a user secrets ID to enable secret storage
list Lists all the application secrets
remove Removes the specified user secret
set Sets the user secret to the specified value
读取保存的内容
在使用的时候需要使用Configuration对象去使用即可。
using Microsoft.AspNetCore.Mvc;
//引入命名空间
using Microsoft.Extensions.Configuration;
namespace WebApplication2.Controllers
{
public class PandaController : Controller
{
public IConfiguration Configuration { get; set; }
//在控制器或者方法中注入配置服务
public string Index([FromServices] IConfiguration configuration)
{
this.Configuration = configuration;
//读取配置项
return Configuration["PandaKey"];
}
}
}
实例:获得数据库配置信息。
var builder = new SqlServerConnectionStringBuilder();
builder.ConnectionString =
Configuration.GetConnectionString("SqlConnection");
builder.Username = Configuration["UserID"];
builder.Password = Configuration["Password"];
services.AddDbContext<CommandContext>
(opt => opt.UseSqlServer(builder.ConnectionString));
File Configuration Provider(文件配置提供程序)
配置说明
SP.NET Core内置了3种格式的配置文件,分别是json、xml、ini,可以通过AddJsonFile、AddXmlFile、AddIniFile来注入对应格式的文件,这些注入方法有4个主要的参数:
-
path:表示配置文件的路径,默认情况下相对于应用程序的运行目录。
-
optional:表示文件是否为可选项。如果指定为true,则忽略文件不存在的情形;如果指定为false,则检测到文件不存在时抛出异常。默认为false。
-
reloadOnChange:表示在文件发生变化时是否重新加载,true表示重新加载变更后的文件,false表示不重新加载,默认为false。
-
provider:表示读取文件的文件提供程序,不传入则表示使用默认的文件提供程序。
此外,框架还提供了AddJsonStream、AddXmlStream、AddIniStream三种方法,可以直接注入文件流。
ConfigurtionBuilder类
ConfigurtionBuilder
类位于Microsoft.Extensions.Configuration
命名空间。
使用时需要引入命名空间
using Microsoft.Extensions.Configuration;
ConfigurtionBuilder
类实现了IConfigurationBuilder
接口,该接口包括两个重要的方法。
namespace Microsoft.Extensions.Configuration
{
public interface IConfigurationBuilder
{
IDictionary<string, object> Properties { get; }
IList<IConfigurationSource> Sources { get; }
//添加不同形式的配置源
IConfigurationBuilder.Add(IConfigurationSource source);
//把所有添加的配置源中配置信息构建(或生成)程序可访问的配置项
IConfigurationRoot.Build();
}
}
使用自定义JSON配置文件
测试使用的JSON文件 UISetting.json
{
"FontFamily": "Arial",
"FontSize": 16,
"Editor": {
"Background": "#F4F4F4",
"Foreground": "Black"
}
}
配置Configuration
服务
打开Program.cs
文件,配置Configuration
对象。
注意:如果是在非ASP.NET Core
应用中使用配置服务,并且使用JSON作为配置文件,需要安装Microsoft.Extensions.Configuration
和Microsoft.Extensions.Configuration.Json
包。
在ASP.NET Core
配置中启用JSON
配置文件。
var builder = WebApplication.CreateBuilder(args);
//直接引入加载的配置文件即可
builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()) //设置配置文件所在的路径
.AddJsonFile("UISetting.json",optional:false, reloadOnChange:true); //添加JSON文件
//或者从文件流读配置
//builder.AddJsonStream(stream: jsonStream);
//Add services to the container
builder.Services.AddControllers();
在Controller
中使用
[HttpGet("ConfigTest")]
public string ConfigTest([FromServices] IConfiguration configuration) //注入配置服务
{
//获得配置文件中的具体值
return configuration["Editor:Background"];
}
读取数据的其他方式
//遍历输出配置项
foreach (var item in config.AsEnumerable())
{
Console.WriteLine($"Key: {item.Key}, Value:{item.Value}");
}
//通过指定索引Key来访问其配置项值
Console.WriteLine("FontFamily: " + config["FontFamily"]);
//通过GetValue方法来访问
Console.WriteLine("FotFamily:" + config.GetValue<int>("FontSize"));
Console.WriteLine("FontSize: " + config.GetValue<int>("FontSize"));
//通过指定索引Key来访问其配置项值(多层级结构)
//使用冒号:即可
Console.WriteLine("Editor Foreground: " + config["Editor:Foreground"]);
//对于层级结构,还可以使用IConfiguration接口的GetSection来访问
var editorSection = config.GetSection("Editor");
Console.WriteLine("Editor Background:" + editorSection["Background"]);
使用自定义XML配置文件
测试使用的XML文件 setting.xml
<?xml version="1.0" encoding="utf-8" ?>
<config>
<AppInfo>
<Name>PandaTestApplication</Name>
<Version>1.0.0</Version>
</AppInfo>
<AuthorInfo>
<Name Code ="666">Panda666</Name>
<Age>18</Age>
</AuthorInfo>
</config>
配置Configuration服务
var builder = WebApplication.CreateBuilder(args);
//直接引入加载的配置文件即可
builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()) //设置配置文件所在的路径
.AddXmlFile("setting.xml", optional:false, reloadOnChange:true); //添加xml文件
//或者从文件流读配置
//builder.AddXmlStream(stream: xmlStream);
// Add services to the container.
builder.Services.AddControllers();
在Controller中使用
//注入配置服务
[HttpGet("ConfigTest")]
public string ConfigTest([FromServices] IConfiguration configuration)
{
//获得配置文件中的具体值
return configuration["AppInfo:Name"];
}
读取数据的其他方式
//遍历输出配置条目
foreach (var item in config.AsEnumerable())
{
//输出条目
Console.WriteLine($"Key: {item.Key}, Value:{item.Value}");
}
//使用字符串索引形式访问
Console.WriteLine("AppInfo:Name: " + config["AppInfo:Name"]);
Console.WriteLine("AppInfo:Version: " + config["AppInfo:Version"]);
Console.WriteLine("AuthorInfo:Name: " + config["AuthorInfo:Name"]);
//访问节点的属性
Console.WriteLine("AuthorInfo:Name:Code: " + config["AuthorInfo:Name:Code"]);
Console.WriteLine("AuthorInfo:Age: " + config["AuthorInfo:Age"]);
//使用GetValue方法访问配置项
Console.WriteLine($"AppInfo:Name = {config.GetValue<string>("AppInfo:Name")}");
Console.WriteLine($"AuthorInfo:Name = {config.GetValue<string>("AuthorInfo:Name")}");
//使用节
var appInfoSection = config.GetSection("AppInfo");
Console.WriteLine($"appInfoSection:AppInfo:Name = {appInfoSection.GetValue<string>("Name")}");
var authorInfoSection = config.GetSection("AuthorInfo");
foreach (var item in appInfoSection.AsEnumerable())
{
Console.WriteLine($"{item.Key} = {item.Value}");
}
foreach (var item in authorInfoSection.AsEnumerable())
{
Console.WriteLine($"{item.Key} = {item.Value}");
}
使用自定义INI配置文件
测试使用的ini
文件 config.ini
[Info]
Name=ConfigTestApp
Version=1.0
Description="这里是INI文件中的描述"
配置Configuration服务
var builder = WebApplication.CreateBuilder(args);
//直接引入加载的配置文件即可
builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()) //设置配置文件所在的路径
.AddIniFile("config.ini", optional:false, reloadOnChange:true); //添加ini文件
//或者从文件流读配置
//builder.AddIniStream(stream: iniStream);
// Add services to the container.
builder.Services.AddControllers();
在Controller
中使用
//注入配置服务
[HttpGet("ConfigTest")]
public string ConfigTest([FromServices] IConfiguration configuration)
{
//获得配置文件中的具体值
return configuration["Info:Name"];
}
读取数据的其他方式
//遍历输出配置条目
foreach (var item in config.AsEnumerable())
{
//输出条目
Console.WriteLine($"Key: {item.Key}, Value:{item.Value}");
}
//使用字符串索引形式访问
Console.WriteLine("AppInfo:Name: " + config["AppInfo:Name"]);
Console.WriteLine("AppInfo:Version: " + config["AppInfo:Version"]);
Console.WriteLine("AuthorInfo:Name: " + config["AuthorInfo:Name"]);
//使用GetValue方法访问配置项
Console.WriteLine($"AppInfo:Name = {config.GetValue<string>("AppInfo:Name")}");
Console.WriteLine($"AuthorInfo:Name = {config.GetValue<string>("AuthorInfo:Name")}");
//使用节
var appInfoSection = config.GetSection("AppInfo");
Console.WriteLine($"appInfoSection:AppInfo:Name = {appInfoSection.GetValue<string>("Name")}");
var authorInfoSection = config.GetSection("AuthorInfo");
foreach (var item in appInfoSection.AsEnumerable())
{
Console.WriteLine($"{item.Key} = {item.Value}");
}
foreach (var item in authorInfoSection.AsEnumerable())
{
Console.WriteLine($"{item.Key} = {item.Value}");
}
Reload Configuration(重新加载配置)
方法一:调用IConfiguration或IConfigurationRoot的Reload方法
config.Reload()
方法二:在添加配置源时指定 reloadOnChange 属性
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("UISetting.json", optional: true,reloadOnChange: true);
Load Configuration From File(从文件夹加载配置文件)
从文件夹加载配置文件可以使用Key-per-file配置提供程序。Key-per-file配置提供程序可将文件内容整体加载为配置值,可以实现的功能如下:
将指定目录下的文件加载到配置程序中,以文件名作为配置的Key值,以文件内容作为配置的Value值。
通过AddKeyPerFile方法可以加载指定目录的文件,它有两个参数:
- directoryPath:表示要加载的目录,必须是绝对路径。
- optional:表示目录是否可选。true表示可选,目录不存在时则忽略;false表示必选,目录不存在时则抛出异常。
实例:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(builder =>
{
//加载配置文件所在的文件夹
var configFileDir = Path.Combine(Directory.GetCurrentDirectory(), "Configs");
//加载文件夹下的配置文件
builder.AddKeyPerFile(directoryPath: configFileDir, optional: false);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
Strong Type(配置强类型对象)
作用
把配置项映射到具体的类型中
访问对象及其属性要比直接访问配置方便
实现
测试使用的配置项 PandaConfig.json
{
"FontSize": 16,
"FontColor": "Red"
}
创建一个包含同样信息的类来表示其中的配置信息
PandaConfig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebApplication1
{
public class PandaConfig
{
public int FontSize { get; set; }
public string FontColor { get; set; }
}
}
在Startup.cs文件中定义配置强类型
public Startup(IConfiguration configuration)
{
Configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("PandaConfig.json")
.Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PandaConfig>(Configuration);
}
Custom Configuration Source(自定义配置源)
说明
使用自定义配置源可以读取特定格式配置文件中的内容
也可以灵活地从配置文件中读取所需要的内容
操作方法
要创建自定义配置源,需要用到两个接口
IConfigurationSource接口
public interface IConfigurationSource
{
IConfigurationProvider Build(IConfigurationBuilder builder);
}
IconfigurationProvider接口
public interface IConfigurationBuilder
{
IDictionary<string, object> Properties { get; }
IList<IConfigurationSource> Sources { get; }
IConfigurationBuilder Add(IConfigurationSource source);
IConfigurationRoot Build();
}
实例:实现加载web.config文件
当要创建的配置源也是基于文件时
可以使用 FileConfigurationSource 和 FileConfigurationProvider 类
两个类分别实现了上述的两个接口,这样就不需要直接去实现上述接口
创建AppSettingsConfigurationSource类
并使它继承FileConfigurationSource类
public class AppSettingsConfigurationSource : FileConfigurationSource
{
public AppSettingsConfigurationSource(string path)
{
Path = path;
ReloadOnChange = true;
Optional = true;
FileProvider = null;
}
public override IConfigurationProvider Build(IConfigurationBuilder builder)
{
FileProvider = FileProvider ?? builder.GetFileProvider();
return new AppSettingsConfigurationProvider(this);
}
}
创建AppSettingsConfigurationProvider类
继承自FileConfigurationProvider类
public class AppSettingsConfigurationProvider : FileConfigurationProvider
{
public AppSettingsConfigurationProvider(AppSettingsConfigura tionSource source) : base(source)
{
}
public override void Load(Stream stream)
{
try
{
Data = ReadAppSettings(stream);
}
catch
{
throw new Exception("读取配置信息失败,可能是文件内容不正确");
}
}
private IDictionary<string, string> ReadAppSettings(Stream stream)
{
var data = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var doc = new XmlDocument();
doc.Load(stream);
var appSettings = doc.SelectNodes("/configuration/appSettings/add");
foreach (XmlNode child in appSettings)
{
data[child.Attributes["key"].Value] = child.Attributes["value"].Value;
}
return data;
}
为了方便使用自定义配置源
可以为IConfigurationBuilder类创建一个扩展方法
public static class AppSettingConfigurationExtensions
{
public static IConfigurationBuilder AddAppSettings(this IconfigurationBuilder builder, string path)
{
return builder.Add(new AppSettingsConfigurationSource(path));
}
}
开始使用
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddAppSettings("web.config");
配置项细节问题
配置项大小写问题
配置项键名不区分大小写
配置项重复问题
同一种类型的配置源可以添加多个,如添加多个JSON格式的配置文件
当指定了多个配置源时,系统会按照顺序加载每个源中的配置项
如果配置源中存在相同键名的配置项,则后面的会将前面的值覆盖
建议将命令行参数配置源作为最后添加的配置源
这样会使命令行参数中的配置项具有最高优先级
它会覆盖之前可能出现过的同名配置项
环境变量配置项冒号问题
当通过环境变量向应用添加配置项时
如果操作系统平台不支持用冒号表示配置项的层次关系
则可以使用双下划线代替冒号,如Editor__Background
不默认支持的配置文件格式
ASP.NET Core提供的配置源中并不支持对web.config或app.config
需要支持这两种或其他类型的配置文件,需要自定义实现配置源
Option(选项组件)
说明
组件定义自己专属的配置对象,也可以叫作选项类,这种设计模式称为选项模式。
使用选项模式可以得到如下好处:
-
符合接口分离原则(ISP)、封装原则,服务、组件仅依赖其用到的配置,而不是整个配置,如IConfiguration对象,它代表了整个应用加载的所有配置,在类中依赖它意味着依赖了整个配置,不符合封装原则。
-
符合关注点分离原则,为服务、组件分别定义选项类,它们之间不相互依赖,确保了组件的独立性。
选项组件主要包含在下列组件包(ASP.NET Core框架已经默认包含了它们)中:
Microsoft.Extensions.Options
Microsoft.Extensions.Options.ConfigurationExtensions
Microsoft.Extensions.Options.DataAnnotations
选项的注入与使用
选项框架提供了一组Configure<TOptions>
扩展方法来注入选项类,可以将配置段Section传入并与其绑定,其中选项类满足下面的条件:
- 必须是非抽象类。
- 必须包含无参数的Public的构造函数。
- 默认绑定所有Public设置了Get、Set属性,可以通过设置支持Private的Set属性。
- 不会绑定字段。
使用实例
先定义一个存储Option的自定义类型
public class MyOption
{
public string Name { get; set; }
public int MinAge { get; set; }
public string Title { get; set; }
}
通过扩展方法Configure
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
//注入MyOption选项类
services.Configure<MyOption>(Configuration.GetSection("myOption"));
//或者使用下面的代码
//注入并设置允许绑定私有属性
services.Configure<MyOption>(Configuration.GetSection("myOption"), binder =>
{
binder.BindNonPublicProperties = true;
});
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//…
}
}
在Service和Controller中使用Option:
public class MyService
{
IOptions<MyOption> _options;
public MyService(IOptions<MyOption> options)
{
_options = options;
}
//其他代码
}
支持注入的IOptions类型
实际上选项框架提供了多个Options接口供选择:
IOptions<out TOptions>:
它的生命周期为单例模式,可以注入任意生命周期的服务中。
不支持配置变更跟踪。不支持命名选项。
适用场景:仅初始化时一次读取,不关心配置变化的服务。
IOptionsSnapshot<TOptions>
它的生命周期为Scope模式,可以注入生命周期为Scope的服务中。
每个Scope都会重新计算选项值,因此可以读到最新的配置值。
支持命名选项。
适用场景:生命周期为Scope且期望在配置变更后使用新值的服务。
IOptionsMonitor<TOptions>
它的生命周期为单例,可以注入任意生命周期的服务中。
它提供了配置变更通知的能力。
支持命名选项。
适用场景:生命周期为单例,并且关心配置变更的服务。
实例:使用IOptionsMonitor类型进行注入
public class MyService2
{
IOptionsMonitor<MyOption> _options;
public MyService2(IOptionsMonitor<MyOption> options)
{
_options = options;
_options.OnChange(option =>
{
Console.WriteLine("配置变化了");
});
}
}
相同命名问题处理
当我们需要在应用中对同一选项类的不同实例配置不同的值时,可以使用命名选项。在使用Configure<TOptions>
时传入name参数,为不同的配置实例指定名称,同时注入各自的配置段,例如使用下面的配置文件:
//默认配置使用Section myOption
services.Configure<MyOption>(Configuration.GetSection("myOption"));
//名称为myOption2的配置使用Section myOption2
services.Configure<MyOption>("myOption2", Configuration.GetSection("myOption2"));
通过OptionsMonitor<TOptions>
的Get方法来读取命名选项类实例:
public class MyService2
{
IOptionsMonitor<MyOption> _options;
public MyService2(IOptionsMonitor<MyOption> options)
{
_options = options;
//默认配置
var option = _options.CurrentValue;
//读取命名配置
var namedOption = _options.Get("myOption2");
_options.OnChange(option =>
{
Console.WriteLine("配置变化了");
});
}
}
验证选项
在需要对选项类值的有效性进行验证的情况下,可以借助选项框架的验证功能来实现选项值的验证。
注入验证逻辑有3种方式:
- 通过DataAnnotations。
- 通过验证委托。
- 通过实现IValidateOptions接口。
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions<MyOption>()
.Bind(Configuration.GetSection("myOption"))
.ValidateDataAnnotations() //启用DataAnnotations验证
.Validate(option => //启用委托验证
{
return option.MinAge >= 0;
}, "MinAge不能小于0");
//启用IValidateOptions验证
services.AddSingleton<IValidateOptions<MyOption>, MyOptionValidation>();
//其他代码
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//…
}
}
注意:要使DataAnnotations方式生效,则需要为选项类添加验证注解。
使用IValidateOptions<MyOption>
验证方式,MyOptionValidation.cs的实现参考:
public class MyOptionValidation : IValidateOptions<MyOption>
{
public ValidateOptionsResult Validate(string name, MyOption options)
{
if (options.MinAge < 0)
{
return ValidateOptionsResult.Fail("MinAge不能小于0");
}
return ValidateOptionsResult.Success;
}
}
标签:Core,ASP,配置文件,builder,配置,json,Configuration,public
From: https://www.cnblogs.com/cqpanda/p/16834832.html