ASP.NET Core教程-Configuration(配置)- 配置文件
更新记录
转载请注明出处:
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;
}
}
作者:重庆熊猫
出处:https://www.cnblogs.com/cqpanda/p/16834832.html
版权:本作品采用「不论是否商业使用都不允许转载,否则按3元1字进行收取费用」许可协议进行许可。
本文来自博客园,作者:重庆熊猫,转载请注明原文链接:https://www.cnblogs.com/cqpanda/p/16834832.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?