ASP.NET Core 中的应用程序配置是使用一个或多个 配置提供程序 执行的。 配置提供程序使用各种配置源从键值对读取配置数据:

  • 设置文件,例如 appsettings.json
  • Azure Key Vault
  • Azure 应用程序配置
  • 命令行参数
  • 已安装或已创建的自定义提供程序
  • 内存中的 .NET 对象
  • 本文介绍 ASP.NET Core 中的配置。 若要了解如何使用控制台应用中的配置,请参阅 .NET 配置

    应用程序和主机配置

    ASP.NET Core 应用配置和启动“主机”。 主机负责应用程序启动和生存期管理。 ASP.NET Core 模板创建的 WebApplicationBuilder 包含主机。 虽然可以在主机和应用程序配置提供程序中完成一些配置,但通常,只有主机必需的配置才应在主机配置中完成。

    应用程序配置具有最高优先级,下一部分对此进行了详细介绍。 主机配置 遵循应用程序配置,本文对此进行了介绍。

    默认应用程序配置源

    通过 dotnet new 或 Visual Studio 创建的 ASP.NET Core Web 应用会生成以下代码:

    var builder = WebApplication.CreateBuilder(args);
    

    WebApplication.CreateBuilder 使用预配置的默认值初始化 类的新实例。 经过初始化的 WebApplicationBuilder (builder) 按照以下顺序为应用提供默认配置(从最高优先级到最低优先级):

  • 使用命令行配置提供程序通过命令行参数提供。
  • 使用非前缀环境变量配置提供程序通过非前缀环境变量提供。
  • 应用在 环境中运行时的用户机密
  • 使用 JSON 配置提供程序通过 appsettings.{Environment}.json 提供。 例如,appsettings.Production.jsonappsettings.Development.json
  • 使用 JSON 配置提供程序通过 appsettings.json 提供。
  • 回退到下一部分所述的主机配置。
  • 默认主机配置源

    以下列表包含 WebApplicationBuilder 的从最高优先级到最低优先级的默认主机配置源:

  • 使用命令行配置提供程序通过命令行参数提供
  • 使用环境变量配置提供程序通过以 DOTNET_ 为前缀的环境变量提供。
  • 使用环境变量配置提供程序通过以 ASPNETCORE_ 为前缀的环境变量提供。
  • 对于 .NET 通用主机Web 主机,从最高优先级到最低优先级的默认主机配置源为:

  • 使用环境变量配置提供程序通过以 ASPNETCORE_ 为前缀的环境变量提供。
  • 使用命令行配置提供程序通过命令行参数提供
  • 使用环境变量配置提供程序通过以 DOTNET_ 为前缀的环境变量提供。
  • 在主机和应用程序配置中设置配置值时,将使用应用程序配置。

    初始化主机生成器时,会提前锁定以下变量,并且它们不受应用程序配置的影响:

  • 应用程序名称
  • 环境名称,例如 DevelopmentProductionStaging
  • 内容根目录
  • Web 根目录
  • 是否要扫描托管启动程序集以及要扫描哪些程序集。
  • 应用和库代码从 IHostBuilder.ConfigureAppConfiguration 回调中的 HostBuilderContext.Configuration 读取的变量。
  • 从应用程序配置而不是主机配置读取所有其他主机设置。

    URLS 是许多不是启动设置的常见主机设置之一。 与不在前一个列表中的所有其他主机设置一样,稍后会从应用程序配置中读取 URLS。主机配置是应用程序配置的后备,因此主机配置可用于设置 URLS,但它将被应用程序配置中的任何配置源(如 appsettings.json)覆盖。

    有关详细信息,请参阅更改内容根、应用名称和环境通过环境变量或命令行更改内容根、应用名称和环境

    本文中的其余部分介绍应用程序配置。

    应用程序配置提供程序

    以下代码按添加顺序显示了已启用的配置提供程序:

    public class Index2Model : PageModel
        private IConfigurationRoot ConfigRoot;
        public Index2Model(IConfiguration configRoot)
            ConfigRoot = (IConfigurationRoot)configRoot;
        public ContentResult OnGet()
            string str = "";
            foreach (var provider in ConfigRoot.Providers.ToList())
                str += provider.ToString() + "\n";
            return Content(str);
    

    前面的优先级从高到低的默认配置源列表以它们被添加到模板生成的应用程序中的相反顺序显示提供程序。 例如,JSON 配置提供程序被添加到命令行配置提供程序之前。

    后来添加的配置提供程序具有更高的优先级并且会替代之前的密钥设置。 例如,如果 appsettings.json 和环境中都设置了 MyKey,则使用环境值。 通过默认配置提供程序,命令行配置提供程序将替代其他所有提供程序。

    若要详细了解 CreateBuilder,请参阅默认生成器设置

    appsettings.json

    请考虑以下 appsettings.json 文件:

    "Position": { "Title": "Editor", "Name": "Joe Smith" "MyKey": "My appsettings.json Value", "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" "AllowedHosts": "*"

    以下来自示例下载的代码显示了上述的一些配置设置:

    public class TestModel : PageModel
        // requires using Microsoft.Extensions.Configuration;
        private readonly IConfiguration Configuration;
        public TestModel(IConfiguration configuration)
            Configuration = configuration;
        public ContentResult OnGet()
            var myKeyValue = Configuration["MyKey"];
            var title = Configuration["Position:Title"];
            var name = Configuration["Position:Name"];
            var defaultLogLevel = Configuration["Logging:LogLevel:Default"];
            return Content($"MyKey value: {myKeyValue} \n" +
                           $"Title: {title} \n" +
                           $"Name: {name} \n" +
                           $"Default Log Level: {defaultLogLevel}");
    

    默认的 JsonConfigurationProvider 会按以下顺序加载配置:

  • appsettings.json
  • appsettings.{Environment}.json:例如,appsettings.Production.jsonappsettings.Development.json 文件。 文件的环境版本是根据 IHostingEnvironment.EnvironmentName 加载的。 有关详细信息,请参阅在 ASP.NET Core 中使用多个环境
  • appsettings.{Environment}.json 值替代 appsettings.json 中的键。 例如,默认情况下:

  • 在开发环境中,appsettings.Development.json 配置会覆盖在 appsettings.json 中找到的值。
  • 在生产环境中,appsettings.Production.json 配置会覆盖在 appsettings.json 中找到的值。 例如,在将应用部署到 Azure 时。
  • 如果必须保证配置值,请参阅 GetValue。 前面的示例只读取字符串,不支持默认值。

    使用默认配置时,会通过 reloadOnChange: true 启用 appsettings.jsonappsettings.{Environment}.json 文件。 应用启动后,对 appsettings.jsonappsettings.{Environment}.json 文件所做的更改将由 JSON 配置提供程序读取。

    appsettings.json 中的注释

    appsettings.jsonappsettings.{Environment}.json 文件中的注释支持使用 JavaScript 或 C# 样式的注释

    使用选项模式绑定分层配置数据

    读取相关配置值的首选方法是使用选项模式。 例如,若要读取以下配置值,请执行以下操作:

      "Position": {
        "Title": "Editor",
        "Name": "Joe Smith"
    

    创建以下 PositionOptions 类:

    public class PositionOptions
        public const string Position = "Position";
        public string Title { get; set; } = String.Empty;
        public string Name { get; set; } = String.Empty;
    
  • 必须是包含公共无参数构造函数的非抽象类。
  • 类型的所有公共读写属性都已绑定。
  • 字段不是绑定的。 在上面的代码中,Position 未绑定。 由于使用了 Position 字段,因此在将类绑定到配置提供程序时,不需要在应用中对字符串 "Position" 进行硬编码。
  • 下面的代码:

  • 调用 ConfigurationBinder.Bind 类绑定到 Position 部分。
  • 显示 Position 配置数据。
  • public class Test22Model : PageModel
        private readonly IConfiguration Configuration;
        public Test22Model(IConfiguration configuration)
            Configuration = configuration;
        public ContentResult OnGet()
            var positionOptions = new PositionOptions();
            Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);
            return Content($"Title: {positionOptions.Title} \n" +
                           $"Name: {positionOptions.Name}");
    

    在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。

    ConfigurationBinder.Get<T> 绑定并返回指定的类型。 使用 ConfigurationBinder.Get<T> 可能比使用 ConfigurationBinder.Bind 更方便。 下面的代码演示如何将 ConfigurationBinder.Get<T>PositionOptions 类配合使用:

    public class Test21Model : PageModel
        private readonly IConfiguration Configuration;
        public PositionOptions? positionOptions { get; private set; }
        public Test21Model(IConfiguration configuration)
            Configuration = configuration;
        public ContentResult OnGet()
            positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                         .Get<PositionOptions>();
            return Content($"Title: {positionOptions.Title} \n" +
                           $"Name: {positionOptions.Name}");
    

    在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。

    使用选项模式时的另一种方法是绑定 Position 部分,并将其添加到依赖关系注入服务容器。 在以下代码中,PositionOptions 已通过 Configure 被添加到了服务容器并已绑定到了配置:

    using ConfigSample.Options;
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddRazorPages();
    builder.Services.Configure<PositionOptions>(
        builder.Configuration.GetSection(PositionOptions.Position));
    var app = builder.Build();
    

    通过使用前面的代码,以下代码将读取位置选项:

    public class Test2Model : PageModel
        private readonly PositionOptions _options;
        public Test2Model(IOptions<PositionOptions> options)
            _options = options.Value;
        public ContentResult OnGet()
            return Content($"Title: {_options.Title} \n" +
                           $"Name: {_options.Name}");
    

    在上面的代码中,不会读取在应用启动后对 JSON 配置文件所做的更改。 若要读取在应用启动后的更改,请使用 IOptionsSnapshot

    使用默认配置时,会通过 reloadOnChange: true 启用 appsettings.jsonappsettings.{Environment}.json 文件。 应用启动后,对 appsettings.jsonappsettings.{Environment}.json 文件所做的更改将由 JSON 配置提供程序读取。

    有关添加其他 JSON 配置文件的信息,请参阅本文档中的 JSON 配置提供程序

    合并服务集合

    考虑下面的方法,该方法可注册服务并配置选项:

    using ConfigSample.Options;
    using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddRazorPages();
    builder.Services.Configure<PositionOptions>(
        builder.Configuration.GetSection(PositionOptions.Position));
    builder.Services.Configure<ColorOptions>(
        builder.Configuration.GetSection(ColorOptions.Color));
    builder.Services.AddScoped<IMyDependency, MyDependency>();
    builder.Services.AddScoped<IMyDependency2, MyDependency2>();
    var app = builder.Build();
    

    可以将相关的注册组移动到扩展方法以注册服务。 例如,配置服务会被添加到以下类中:

    using ConfigSample.Options;
    using Microsoft.Extensions.Configuration;
    namespace Microsoft.Extensions.DependencyInjection
        public static class MyConfigServiceCollectionExtensions
            public static IServiceCollection AddConfig(
                 this IServiceCollection services, IConfiguration config)
                services.Configure<PositionOptions>(
                    config.GetSection(PositionOptions.Position));
                services.Configure<ColorOptions>(
                    config.GetSection(ColorOptions.Color));
                return services;
            public static IServiceCollection AddMyDependencyGroup(
                 this IServiceCollection services)
                services.AddScoped<IMyDependency, MyDependency>();
                services.AddScoped<IMyDependency2, MyDependency2>();
                return services;
    

    剩余的服务会在类似的类中注册。 下面的代码使用新扩展方法来注册服务:

    using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
    var builder = WebApplication.CreateBuilder(args);
    builder.Services
        .AddConfig(builder.Configuration)
        .AddMyDependencyGroup();
    builder.Services.AddRazorPages();
    var app = builder.Build();
    

    注意:每个 services.Add{GROUP_NAME} 扩展方法添加并可能配置服务。 例如,AddControllersWithViews 会添加带视图的 MVC 控制器所需的服务,AddRazorPages 会添加 Razor Pages 所需的服务。

    安全性和用户机密

    配置数据指南:

  • 请勿在配置提供程序代码或纯文本配置文件中存储密码或其他敏感数据。 机密管理器工具可用于存储开发环境中的机密。
  • 不要在开发或测试环境中使用生产机密。
  • 请在项目外部指定机密,避免将其意外提交到源代码存储库。
  • 默认情况下,将在 JSON 配置源后注册用户机密配置源。 因此,用户机密密钥优先于 appsettings.jsonappsettings.{Environment}.json 中的密钥。

    有关存储密码或其他敏感数据的详细信息:

  • 在 ASP.NET Core 中使用多个环境
  • 在 ASP.NET Core 开发环境中安全存储应用机密:包括有关使用环境变量存储敏感数据的建议。 机密管理器工具使用文件配置提供程序将用户机密存储在本地系统上的 JSON 文件中。
  • Azure Key Vault 安全存储 ASP.NET Core 应用的应用机密。 有关详细信息,请参阅 ASP.NET Core 中的 Azure Key Vault 配置提供程序

    非前缀环境变量

    非前缀环境变量不是以ASPNETCORE_DOTNET_ 为前缀的环境变量。 例如,launchSettings.json 中的 ASP.NET Core Web 应用程序模板设置集 "ASPNETCORE_ENVIRONMENT": "Development"。 有关 ASPNETCORE_DOTNET_ 环境变量的详细信息,请参阅以下内容:

  • 最高到最低优先级的默认配置源列表,包括非前缀、以 ASPNETCORE_ 为前缀和以 DOTNETCORE_ 为前缀的环境变量。
  • Microsoft.Extensions.Hosting 外部使用的 DOTNET_ 环境变量。
  • 使用默认配置时,EnvironmentVariablesConfigurationProvider 会在读取 appsettings.jsonappsettings.{Environment}.json用户机密之后,从环境变量键值对中加载配置。 因此,从环境中读取的键值会替代从 appsettings.jsonappsettings.{Environment}.json 和用户机密中读取的值。

    所有平台上的环境变量分层键都不支持 : 分隔符。 __(双下划线):

  • 受所有平台支持。 例如,Bash 不支持 : 分隔符,但支持 __
  • 自动替换为 :
  • 以下 set 命令:

  • 在 Windows 上设置上述示例的环境键和值。
  • 在使用示例下载时测试设置。 dotnet run 命令必须在项目目录中运行。
  • set MyKey="My key from Environment"
    set Position__Title=Environment_Editor
    set Position__Name=Environment_Rick
    dotnet run
    

    前面的环境设置:

  • 仅在进程中设置,这些进程是从设置进程的命令窗口启动的。
  • 不会由通过 Visual Studio 启动的浏览器读取。
  • 以下 setx 命令可用于在 Windows 上设置环境键和值。 与 set 不同,setx 设置是持久的。 /M 在系统环境中设置变量。 如果未使用 /M 开关,则会设置用户环境变量。

    setx MyKey "My key from setx Environment" /M
    setx Position__Title Environment_Editor /M
    setx Position__Name Environment_Rick /M
    

    测试前面的命令是否会替代 appsettings.jsonappsettings.{Environment}.json

  • 使用 Visual Studio:退出并重启 Visual Studio。
  • 使用 CLI:启动新的命令窗口并输入 dotnet run
  • 使用字符串调用 AddEnvironmentVariables 以指定环境变量的前缀:

    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddRazorPages();
    builder.Configuration.AddEnvironmentVariables(prefix: "MyCustomPrefix_");
    var app = builder.Build();
    

    在上述代码中:

  • builder.Configuration.AddEnvironmentVariables(prefix: "MyCustomPrefix_") 被添加到默认配置提供程序之后。 有关对配置提供程序进行排序的示例,请参阅 JSON 配置提供程序
  • 使用 MyCustomPrefix_ 前缀设置的环境变量将替代默认配置提供程序。 这包括没有前缀的环境变量。
  • 前缀会在读取配置键值对时被去除。

    以下命令对自定义前缀进行测试:

    set MyCustomPrefix_MyKey="My key with MyCustomPrefix_ Environment"
    set MyCustomPrefix_Position__Title=Editor_with_customPrefix
    set MyCustomPrefix_Position__Name=Environment_Rick_cp
    dotnet run
    

    默认配置会加载前缀为 DOTNET_ASPNETCORE_ 的环境变量和命令行参数。 DOTNET_ASPNETCORE_ 前缀会由 ASP.NET Core 用于主机和应用配置,但不用于用户配置。 有关主机和应用配置的详细信息,请参阅 .NET 通用主机

    Azure 应用服务上,选择“设置”>“配置”页面上的“新应用程序设置”。 Azure 应用服务应用程序设置:

  • 已静态加密且通过加密的通道进行传输。
  • 已作为环境变量公开。
  • 有关详细信息,请参阅 Azure 应用:使用 Azure 门户替代应用配置

    有关 Azure 数据库连接字符串的信息,请参阅连接字符串前缀

    环境变量的命名

    环境变量名称反映了 appsettings.json 文件的结构。 层次结构中的每个元素由双下划线字符(更可取)或冒号分隔。 当元素结构包含数组时,应将数组索引视为此路径中的附加元素名称。 请考虑以下 appsettings.json 文件及其表示为环境变量的等效值。

    appsettings.json

    "SmtpServer": "smtp.example.com", "Logging": [ "Name": "ToEmail", "Level": "Critical", "Args": { "FromAddress": "MySystem@example.com", "ToAddress": "SRE@example.com" "Name": "ToConsole", "Level": "Information"
    setx SmtpServer smtp.example.com
    setx Logging__0__Name ToEmail
    setx Logging__0__Level Critical
    setx Logging__0__Args__FromAddress MySystem@example.com
    setx Logging__0__Args__ToAddress SRE@example.com
    setx Logging__1__Name ToConsole
    setx Logging__1__Level Information
    

    在生成的 launchSettings.json 中设置的环境变量

    launchSettings.json 中设置的环境变量将替代在系统环境中设置的变量。 例如,ASP.NET Core Web 模板会生成一个 launchSettings.json 文件,该文件将终结点配置设置为:

    "applicationUrl": "https://localhost:5001;http://localhost:5000"
    

    配置 applicationUrl 将设置 ASPNETCORE_URLS 环境变量并重写环境中设置的值。

    在 Linux 上转义环境变量

    在 Linux 上,必须转义 URL 环境变量的值,使 systemd 可以对其进行分析。 使用 Linux 工具 systemd-escape 生成 http:--localhost:5001

    groot@terminus:~$ systemd-escape http://localhost:5001
    http:--localhost:5001
    

    显示环境变量

    下面的代码显示了应用程序启动时的环境变量和值,这对调试环境设置很有帮助:

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    foreach (var c in builder.Configuration.AsEnumerable())
        Console.WriteLine(c.Key + " = " + c.Value);
    

    使用默认配置,CommandLineConfigurationProvider 会从以下配置源后的命令行参数键值对中加载配置:

  • appsettings.jsonappsettings.{Environment}.json 文件。
  • 开发环境中的应用机密
  • 环境变量。
  • 默认情况下,在命令行上设置的配置值会替代通过所有其他配置提供程序设置的配置值。

    命令行参数

    以下命令使用 = 设置键和值:

    dotnet run MyKey="Using =" Position:Title=Cmd Position:Name=Cmd_Rick
    

    以下命令使用 / 设置键和值:

    dotnet run /MyKey "Using /" /Position:Title=Cmd /Position:Name=Cmd_Rick
    

    以下命令使用 -- 设置键和值:

    dotnet run --MyKey "Using --" --Position:Title=Cmd --Position:Name=Cmd_Rick
    
  • 必须后跟 =,或者当值后跟一个空格时,键必须具有一个 --/ 的前缀。
  • 如果使用 =,则不是必需的。 例如 MySetting=
  • 在同一命令中,请勿将使用 = 的命令行参数键值对与使用空格的键值对混合使用。

    交换映射支持键名替换逻辑。 提供针对 AddCommandLine 方法的交换替换字典。

    当使用交换映射字典时,会检查字典中是否有与命令行参数提供的键匹配的键。 如果在字典中找到了命令行键,则会传回字典值将键值对设置为应用的配置。 对任何具有单划线 (-) 前缀的命令行键而言,交换映射都是必需的。

    交换映射字典键规则:

  • 交换必须以 --- 开头。
  • 交换映射字典不得包含重复键。
  • 若要使用交换映射字典,请将它传递到对 AddCommandLine 的调用中:

    var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorPages(); var switchMappings = new Dictionary<string, string>() { "-k1", "key1" }, { "-k2", "key2" }, { "--alt3", "key3" }, { "--alt4", "key4" }, { "--alt5", "key5" }, { "--alt6", "key6" }, builder.Configuration.AddCommandLine(args, switchMappings); var app = builder.Build();

    运行以下命令可测试键替换:

    dotnet run -k1 value1 -k2 value2 --alt3=value2 /alt4=value3 --alt5 value5 /alt6 value6
    

    下面的代码显示了替换后的键的键值:

    public class Test3Model : PageModel
        private readonly IConfiguration Config;
        public Test3Model(IConfiguration configuration)
            Config = configuration;
        public ContentResult OnGet()
            return Content(
                    $"Key1: '{Config["Key1"]}'\n" +
                    $"Key2: '{Config["Key2"]}'\n" +
                    $"Key3: '{Config["Key3"]}'\n" +
                    $"Key4: '{Config["Key4"]}'\n" +
                    $"Key5: '{Config["Key5"]}'\n" +
                    $"Key6: '{Config["Key6"]}'");
    

    对于使用交换映射的应用,调用 CreateDefaultBuilder 不应传递参数。 CreateDefaultBuilder 方法的 AddCommandLine 调用不包括映射的交换,并且无法将交换映射字典传递给 CreateDefaultBuilder。 解决方案不是将参数传递给 CreateDefaultBuilder,而是允许 ConfigurationBuilder 方法的 AddCommandLine 方法处理参数和交换映射字典。

    在 Visual Studio 中设置环境和命令行参数

    可以在 Visual Studio 中的“启动配置文件”对话框设置环境和命令行参数:

  • 在“解决方案资源管理器”中,右键单击项目,然后选择“属性”。
  • 转到“调试”>“常规”选项卡,然后选择“打开调试启动配置文件 UI”>
  • 分层配置数据

    配置 API 在配置键中使用分隔符来展平分层数据,以此来读取分层配置数据。

    示例下载包含以下 appsettings.json 文件:

    "Position": { "Title": "Editor", "Name": "Joe Smith" "MyKey": "My appsettings.json Value", "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" "AllowedHosts": "*"

    以下来自示例下载的代码显示了一些配置设置:

    public class TestModel : PageModel
        // requires using Microsoft.Extensions.Configuration;
        private readonly IConfiguration Configuration;
        public TestModel(IConfiguration configuration)
            Configuration = configuration;
        public ContentResult OnGet()
            var myKeyValue = Configuration["MyKey"];
            var title = Configuration["Position:Title"];
            var name = Configuration["Position:Name"];
            var defaultLogLevel = Configuration["Logging:LogLevel:Default"];
            return Content($"MyKey value: {myKeyValue} \n" +
                           $"Title: {title} \n" +
                           $"Name: {name} \n" +
                           $"Default Log Level: {defaultLogLevel}");
    

    读取分层配置数据的首选方法是使用选项模式。 有关详细信息,请参阅本文档中的绑定分层配置数据

    GetSectionGetChildren 方法可用于隔离各个节和配置数据中某节的子节。 稍后将在 GetSection、GetChildren 和 Exists 中介绍这些方法。

    配置键和值

  • 不区分大小写。 例如,ConnectionStringconnectionstring 被视为等效键。
  • 如果在多个配置提供程序中设置了某一键和值,则会使用最后添加的提供程序中的值。 有关详细信息,请参阅默认配置
  • 在配置 API 中,冒号分隔符 (:) 适用于所有平台。
  • 在环境变量中,冒号分隔符可能无法适用于所有平台。 所有平台均支持采用双下划线 __,并且它会自动转换为冒号 :
  • 在 Azure Key Vault 中,分层键使用 -- 作为分隔符。 当机密加载到应用的配置中时,Azure Key Vault 配置提供程序 会自动将 -- 替换为 :
  • ConfigurationBinder 支持使用配置键中的数组索引将数组绑定到对象。 数组绑定将在将数组绑定到类部分中进行介绍。
  • 为字符串。
  • NULL 值不能存储在配置中或绑定到对象。
  • 配置提供程序

    下表显示了 ASP.NET Core 应用可用的配置提供程序。

    通过以下对象提供配置 MYSQLCONNSTR_{KEY} ConnectionStrings:{KEY} 键:ConnectionStrings:{KEY}_ProviderName
    值:MySql.Data.MySqlClient SQLAZURECONNSTR_{KEY} ConnectionStrings:{KEY} 键:ConnectionStrings:{KEY}_ProviderName
    值:System.Data.SqlClient SQLCONNSTR_{KEY} ConnectionStrings:{KEY} 键:ConnectionStrings:{KEY}_ProviderName
    值:System.Data.SqlClient

    FileConfigurationProvider 是从文件系统加载配置的基类。 以下配置提供程序派生自 FileConfigurationProvider

  • INI 配置提供程序
  • JSON 配置提供程序
  • XML 配置提供程序
  • INI 配置提供程序

    IniConfigurationProvider 在运行时从 INI 文件键值对加载配置。

    以下代码添加多个配置提供程序:

    var builder = WebApplication.CreateBuilder(args);
    builder.Configuration
        .AddIniFile("MyIniConfig.ini", optional: true, reloadOnChange: true)
        .AddIniFile($"MyIniConfig.{builder.Environment.EnvironmentName}.ini",
                    optional: true, reloadOnChange: true);
    builder.Configuration.AddEnvironmentVariables();
    builder.Configuration.AddCommandLine(args);
    builder.Services.AddRazorPages();
    var app = builder.Build();
    

    在前面的代码中,MyIniConfig.iniMyIniConfig.{Environment}.ini 文件中的设置会被以下提供程序中的设置替代:

  • 环境变量配置提供程序
  • 命令行配置提供程序
  • 示例下载包含以下 MyIniConfig.ini 文件:

    MyKey="MyIniConfig.ini Value"
    [Position]
    Title="My INI Config title"
    Name="My INI Config name"
    [Logging:LogLevel]
    Default=Information
    Microsoft=Warning
    

    以下来自示例下载的代码显示了上述的一些配置设置:

    public class TestModel : PageModel
        // requires using Microsoft.Extensions.Configuration;
        private readonly IConfiguration Configuration;
        public TestModel(IConfiguration configuration)
            Configuration = configuration;
        public ContentResult OnGet()
            var myKeyValue = Configuration["MyKey"];
            var title = Configuration["Position:Title"];
            var name = Configuration["Position:Name"];
            var defaultLogLevel = Configuration["Logging:LogLevel:Default"];
            return Content($"MyKey value: {myKeyValue} \n" +
                           $"Title: {title} \n" +
                           $"Name: {name} \n" +
                           $"Default Log Level: {defaultLogLevel}");
    

    JSON 配置提供程序

    JsonConfigurationProvider 从 JSON 文件键值对加载配置。

    重载可以指定:

  • 文件是否可选。
  • 如果文件更改,是否重载配置。
  • 考虑下列代码:

    using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
    var builder = WebApplication.CreateBuilder(args);
    builder.Configuration.AddJsonFile("MyConfig.json",
            optional: true,
            reloadOnChange: true);
    builder.Services.AddRazorPages();
    var app = builder.Build();
    

    前面的代码:

  • 通过以下选项将 JSON 配置提供程序配置为加载 MyConfig.json 文件:
    • optional: true:文件是可选的。
    • reloadOnChange: true:保存更改后会重载文件。
    • 读取 MyConfig.json 文件之前的默认配置提供程序MyConfig.json 文件中的设置会替代默认配置提供程序中的设置,包括环境变量配置提供程序命令行配置提供程序
    • 通常,你不会希望自定义 JSON 文件替代在环境变量配置提供程序命令行配置提供程序中设置的值

      XML 配置提供程序

      XmlConfigurationProvider 在运行时从 XML 文件键值对加载配置。

      以下代码添加多个配置提供程序:

      var builder = WebApplication.CreateBuilder(args);
      builder.Configuration
          .AddXmlFile("MyXMLFile.xml", optional: true, reloadOnChange: true)
          .AddXmlFile($"MyXMLFile.{builder.Environment.EnvironmentName}.xml",
                      optional: true, reloadOnChange: true);
      builder.Configuration.AddEnvironmentVariables();
      builder.Configuration.AddCommandLine(args);
      builder.Services.AddRazorPages();
      var app = builder.Build();
      

      在前面的代码中,MyXMLFile.xmlMyXMLFile.{Environment}.xml 文件中的设置会被以下提供程序中的设置替代:

    • 环境变量配置提供程序
    • 命令行配置提供程序
    • 示例下载包含以下 MyXMLFile.xml 文件:

      <?xml version="1.0" encoding="utf-8" ?>
      <configuration>
        <MyKey>MyXMLFile Value</MyKey>
        <Position>
          <Title>Title from  MyXMLFile</Title>
          <Name>Name from MyXMLFile</Name>
        </Position>
        <Logging>
          <LogLevel>
            <Default>Information</Default>
            <Microsoft>Warning</Microsoft>
          </LogLevel>
        </Logging>
      </configuration>
      

      以下来自示例下载的代码显示了上述的一些配置设置:

      public class TestModel : PageModel
          // requires using Microsoft.Extensions.Configuration;
          private readonly IConfiguration Configuration;
          public TestModel(IConfiguration configuration)
              Configuration = configuration;
          public ContentResult OnGet()
              var myKeyValue = Configuration["MyKey"];
              var title = Configuration["Position:Title"];
              var name = Configuration["Position:Name"];
              var defaultLogLevel = Configuration["Logging:LogLevel:Default"];
              return Content($"MyKey value: {myKeyValue} \n" +
                             $"Title: {title} \n" +
                             $"Name: {name} \n" +
                             $"Default Log Level: {defaultLogLevel}");
      

      如果使用 name 属性来区分元素,则使用相同元素名称的重复元素可以正常工作:

      <?xml version="1.0" encoding="UTF-8"?>
      <configuration>
        <section name="section0">
          <key name="key0">value 00</key>
          <key name="key1">value 01</key>
        </section>
        <section name="section1">
          <key name="key0">value 10</key>
          <key name="key1">value 11</key>
        </section>
      </configuration>
      

      以下代码会读取前面的配置文件并显示键和值:

      public class IndexModel : PageModel
          private readonly IConfiguration Configuration;
          public IndexModel(IConfiguration configuration)
              Configuration = configuration;
          public ContentResult OnGet()
              var key00 = "section:section0:key:key0";
              var key01 = "section:section0:key:key1";
              var key10 = "section:section1:key:key0";
              var key11 = "section:section1:key:key1";
              var val00 = Configuration[key00];
              var val01 = Configuration[key01];
              var val10 = Configuration[key10];
              var val11 = Configuration[key11];
              return Content($"{key00} value: {val00} \n" +
                             $"{key01} value: {val01} \n" +
                             $"{key10} value: {val10} \n" +
                             $"{key10} value: {val11} \n"
      

      属性可用于提供值:

      <?xml version="1.0" encoding="UTF-8"?>
      <configuration>
        <key attribute="value" />
        <section>
          <key attribute="value" />
        </section>
      </configuration>
      

      以前的配置文件使用 value 加载以下键:

    • key:attribute
    • section:key:attribute
    • Key-per-file 配置提供程序

      KeyPerFileConfigurationProvider 使用目录的文件作为配置键值对。 该键是文件名。 该值包含文件的内容。 Key-per-file 配置提供程序用于 Docker 托管方案。

      若要激活 Key-per-file 配置,请在 ConfigurationBuilder 的实例上调用 AddKeyPerFile 扩展方法。 文件的 directoryPath 必须是绝对路径。

      重载允许指定:

    • 配置源的 Action<KeyPerFileConfigurationSource> 委托。
    • 目录是否可选以及目录的路径。
    • 双下划线字符 (__) 用作文件名中的配置键分隔符。 例如,文件名 Logging__LogLevel__System 生成配置键 Logging:LogLevel:System

      构建主机时调用 ConfigureAppConfiguration 以指定应用的配置:

      .ConfigureAppConfiguration((hostingContext, config) =>
          var path = Path.Combine(
              Directory.GetCurrentDirectory(), "path/to/files");
          config.AddKeyPerFile(directoryPath: path, optional: true);
      

      内存配置提供程序

      MemoryConfigurationProvider 使用内存中集合作为配置键值对。

      以下代码将内存集合添加到配置系统中:

      var builder = WebApplication.CreateBuilder(args);
      var Dict = new Dictionary<string, string>
                 {"MyKey", "Dictionary MyKey Value"},
                 {"Position:Title", "Dictionary_Title"},
                 {"Position:Name", "Dictionary_Name" },
                 {"Logging:LogLevel:Default", "Warning"}
      builder.Configuration.AddInMemoryCollection(Dict);
      builder.Configuration.AddEnvironmentVariables();
      builder.Configuration.AddCommandLine(args);
      builder.Services.AddRazorPages();
      var app = builder.Build();
      

      以下来自示例下载的代码显示了上述配置设置:

      public class TestModel : PageModel
          // requires using Microsoft.Extensions.Configuration;
          private readonly IConfiguration Configuration;
          public TestModel(IConfiguration configuration)
              Configuration = configuration;
          public ContentResult OnGet()
              var myKeyValue = Configuration["MyKey"];
              var title = Configuration["Position:Title"];
              var name = Configuration["Position:Name"];
              var defaultLogLevel = Configuration["Logging:LogLevel:Default"];
              return Content($"MyKey value: {myKeyValue} \n" +
                             $"Title: {title} \n" +
                             $"Name: {name} \n" +
                             $"Default Log Level: {defaultLogLevel}");
      

      在前面的代码中,config.AddInMemoryCollection(Dict) 会被添加到默认配置提供程序之后。 有关对配置提供程序进行排序的示例,请参阅 JSON 配置提供程序

      有关使用 MemoryConfigurationProvider 的其他示例,请参阅绑定数组

      Kestrel 终结点配置

      Kestrel 特定的终结点配置将覆盖所有跨服务器终结点配置。 跨服务器终结点配置包括:

    • UseUrls
    • 命令行上的 --urls
    • 环境变量ASPNETCORE_URLS
    • 请考虑在 ASP.NET Core Web 应用中使用的以下 appsettings.json 文件:

      "Kestrel": { "Endpoints": { "Https": { "Url": "https://localhost:9999" "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" "AllowedHosts": "*"

      当在 ASP.NET Core Web 应用中使用前面突出显示的标记,并且应用在命令行上启动,且跨服务器端点配置如下时

      dotnet run --urls="https://localhost:7777"

      Kestrel 将绑定到专门针对 appsettings.json 文件中的 Kestrel 配置的终结点 (https://localhost:9999),而不是 https://localhost:7777

      请考虑将 Kestrel 特定的终结点配置为环境变量:

      set Kestrel__Endpoints__Https__Url=https://localhost:8888

      在前面的环境变量中,Https 是 Kestrel 特定的终结点的名称。 前面的 appsettings.json 文件还定义了名为 Https 的 Kestrel 特定终结点。 默认情况下,将在 appsettings.{Environment}.json 后读取使用环境变量配置提供程序的环境变量,因此,前面的环境变量用于 Https 终结点。

      GetValue

      ConfigurationBinder.GetValue 从配置中提取一个具有指定键的值,并将它转换为指定的类型:

      public class TestNumModel : PageModel
          private readonly IConfiguration Configuration;
          public TestNumModel(IConfiguration configuration)
              Configuration = configuration;
          public ContentResult OnGet()
              var number = Configuration.GetValue<int>("NumberKey", 99);
              return Content($"{number}");
      

      在前面的代码中,如果在配置中找不到 NumberKey,则使用默认值 99

      GetSection、GetChildren 和 Exists

      对于下面的示例,请考虑以下 MySubsection.json 文件:

      "section0": { "key0": "value00", "key1": "value01" "section1": { "key0": "value10", "key1": "value11" "section2": { "subsection0": { "key0": "value200", "key1": "value201" "subsection1": { "key0": "value210", "key1": "value211"

      以下代码将 MySubsection.json 添加到配置提供程序:

      var builder = WebApplication.CreateBuilder(args);
      builder.Configuration
          .AddJsonFile("MySubsection.json",
                       optional: true,
                       reloadOnChange: true);
      builder.Services.AddRazorPages();
      var app = builder.Build();
      

      GetSection

      IConfiguration.GetSection 会返回具有指定子节键的配置子节。

      以下代码将返回 section1 的值:

      public class TestSectionModel : PageModel
          private readonly IConfiguration Config;
          public TestSectionModel(IConfiguration configuration)
              Config = configuration.GetSection("section1");
          public ContentResult OnGet()
              return Content(
                      $"section1:key0: '{Config["key0"]}'\n" +
                      $"section1:key1: '{Config["key1"]}'");
      

      以下代码将返回 section2:subsection0 的值:

      public class TestSection2Model : PageModel
          private readonly IConfiguration Config;
          public TestSection2Model(IConfiguration configuration)
              Config = configuration.GetSection("section2:subsection0");
          public ContentResult OnGet()
              return Content(
                      $"section2:subsection0:key0 '{Config["key0"]}'\n" +
                      $"section2:subsection0:key1:'{Config["key1"]}'");
      

      GetSection 永远不会返回 null。 如果找不到匹配的节,则返回空 IConfigurationSection

      GetSection 返回匹配的部分时,Value 未填充。 存在该部分时,返回一个 KeyPath 部分。

      GetChildren 和 Exists

      以下代码将调用 IConfiguration.GetChildren 并返回 section2:subsection0 的值:

      public class TestSection4Model : PageModel
          private readonly IConfiguration Config;
          public TestSection4Model(IConfiguration configuration)
              Config = configuration;
          public ContentResult OnGet()
              string s = "";
              var selection = Config.GetSection("section2");
              if (!selection.Exists())
                  throw new Exception("section2 does not exist.");
              var children = selection.GetChildren();
              foreach (var subSection in children)
                  int i = 0;
                  var key1 = subSection.Key + ":key" + i++.ToString();
                  var key2 = subSection.Key + ":key" + i.ToString();
                  s += key1 + " value: " + selection[key1] + "\n";
                  s += key2 + " value: " + selection[key2] + "\n";
              return Content(s);
      

      前面的代码将调用 ConfigurationExtensions.Exists 以验证该节是否存在:

      ConfigurationBinder.Bind 支持使用配置键中的数组索引将数组绑定到对象。 公开数值键段的任何数组格式都能够与 POCO 类数组进行数组绑定。

      请考虑示例下载中的 MyArray.json

      "array": { "entries": { "0": "value00", "1": "value10", "2": "value20", "4": "value40", "5": "value50"

      以下代码将 MyArray.json 添加到配置提供程序:

      var builder = WebApplication.CreateBuilder(args);
      builder.Configuration
          .AddJsonFile("MyArray.json",
                       optional: true,
                       reloadOnChange: true);
      builder.Services.AddRazorPages();
      var app = builder.Build();
      

      以下代码将读取配置并显示值:

      public class ArrayModel : PageModel
          private readonly IConfiguration Config;
          public ArrayExample? _array { get; private set; }
          public ArrayModel(IConfiguration config)
              Config = config;
          public ContentResult OnGet()
             _array = Config.GetSection("array").Get<ArrayExample>();
              if (_array == null)
                  throw new ArgumentNullException(nameof(_array));
              string s = String.Empty;
              for (int j = 0; j < _array.Entries.Length; j++)
                  s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
              return Content(s);
      
      public class ArrayExample
          public string[]? Entries { get; set; } 
      

      前面的代码会返回以下输出:

      Index: 0  Value: value00
      Index: 1  Value: value10
      Index: 2  Value: value20
      Index: 3  Value: value40
      Index: 4  Value: value50
      

      在前面的输出中,索引 3 具有值 value40,与 MyArray.json 中的 "4": "value40", 相对应。 绑定的数组索引是连续的,并且未绑定到配置键索引。 配置绑定器不能绑定 NULL 值,也不能在绑定的对象中创建 NULL 条目。

      自定义配置提供程序

      该示例应用演示了如何使用实体框架 (EF) 创建从数据库读取配置键值对的基本配置提供程序。

      提供程序具有以下特征:

    • EF 内存中数据库用于演示目的。 若要使用需要连接字符串的数据库,请实现辅助 ConfigurationBuilder 以从另一个配置提供程序提供连接字符串。
    • 提供程序在启动时将数据库表读入配置。 提供程序不会基于每个键查询数据库。
    • 未实现更改时重载,因此在应用启动后更新数据库对应用的配置没有任何影响。
    • 定义用于在数据库中存储配置值的 EFConfigurationValue 实体。

      Models/EFConfigurationValue.cs:

      public class EFConfigurationValue
          public string Id { get; set; } = String.Empty;
          public string Value { get; set; } = String.Empty;
      

      添加 EFConfigurationContext 以存储和访问配置的值。

      EFConfigurationProvider/EFConfigurationContext.cs:

      public class EFConfigurationContext : DbContext
          public EFConfigurationContext(DbContextOptions<EFConfigurationContext> options) : base(options)
          public DbSet<EFConfigurationValue> Values => Set<EFConfigurationValue>();
      

      创建用于实现 IConfigurationSource 的类。

      EFConfigurationProvider/EFConfigurationSource.cs:

      public class EFConfigurationSource : IConfigurationSource
          private readonly Action<DbContextOptionsBuilder> _optionsAction;
          public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction) => _optionsAction = optionsAction;
          public IConfigurationProvider Build(IConfigurationBuilder builder) => new EFConfigurationProvider(_optionsAction);
      

      通过从 ConfigurationProvider 继承来创建自定义配置提供程序。 当数据库为空时,配置提供程序将对其进行初始化。 由于配置密钥不区分大小写,因此用来初始化数据库的字典是用不区分大小写的比较程序 (StringComparer.OrdinalIgnoreCase) 创建的。

      EFConfigurationProvider/EFConfigurationProvider.cs:

      public class EFConfigurationProvider : ConfigurationProvider
          public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
              OptionsAction = optionsAction;
          Action<DbContextOptionsBuilder> OptionsAction { get; }
          public override void Load()
              var builder = new DbContextOptionsBuilder<EFConfigurationContext>();
              OptionsAction(builder);
              using (var dbContext = new EFConfigurationContext(builder.Options))
                  if (dbContext == null || dbContext.Values == null)
                      throw new Exception("Null DB context");
                  dbContext.Database.EnsureCreated();
                  Data = !dbContext.Values.Any()
                      ? CreateAndSaveDefaultValues(dbContext)
                      : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
          private static IDictionary<string, string> CreateAndSaveDefaultValues(
              EFConfigurationContext dbContext)
              // Quotes (c)2005 Universal Pictures: Serenity
              // https://www.uphe.com/movies/serenity-2005
              var configValues =
                  new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
                          { "quote1", "I aim to misbehave." },
                          { "quote2", "I swallowed a bug." },
                          { "quote3", "You can't stop the signal, Mal." }
              if (dbContext == null || dbContext.Values == null)
                  throw new Exception("Null DB context");
              dbContext.Values.AddRange(configValues
                  .Select(kvp => new EFConfigurationValue
                      Id = kvp.Key,
                      Value = kvp.Value
                  .ToArray());
              dbContext.SaveChanges();
              return configValues;
      

      可以使用 AddEFConfiguration 扩展方法将配置源添加到 ConfigurationBuilder

      Extensions/EntityFrameworkExtensions.cs:

      public static class EntityFrameworkExtensions
          public static IConfigurationBuilder AddEFConfiguration(
                     this IConfigurationBuilder builder,
                     Action<DbContextOptionsBuilder> optionsAction)
              return builder.Add(new EFConfigurationSource(optionsAction));
      

      下面的代码演示如何在 Program.cs 中使用自定义的 EFConfigurationProvider

      //using Microsoft.EntityFrameworkCore;
      var builder = WebApplication.CreateBuilder(args);
      builder.Configuration.AddEFConfiguration(
          opt => opt.UseInMemoryDatabase("InMemoryDb"));
      var app = builder.Build();
      app.Run();
      

      使用依赖关系注入 (DI) 的访问配置

      通过解析 IConfiguration 服务,可以使用依赖关系注入 (DI) 将配置注入服务:

      public class Service
          private readonly IConfiguration _config;
          public Service(IConfiguration config) =>
              _config = config;
          public void DoSomething()
              var configSettingValue = _config["ConfigSetting"];
              // ...
      

      有关如何使用 IConfiguration 访问值的信息,请参阅本文中的 GetValue 以及 GetSection、GetChildren 和 Exists

      访问 Razor Pages 中的配置

      以下代码显示 Razor Pages 中的配置数据:

      @page
      @model Test5Model
      @using Microsoft.Extensions.Configuration
      @inject IConfiguration Configuration
      Configuration value for 'MyKey': @Configuration["MyKey"]
      

      在以下代码中,MyOptions 已通过 Configure 被添加到了服务容器并已绑定到了配置:

      using SampleApp.Models;
      var builder = WebApplication.CreateBuilder(args);
      builder.Services.AddRazorPages();
      builder.Services.Configure<MyOptions>(
          builder.Configuration.GetSection("MyOptions"));
      var app = builder.Build();
      

      以下标记使用 @injectRazor 指令来解析和显示选项值:

      @page
      @model SampleApp.Pages.Test3Model
      @using Microsoft.Extensions.Options
      @using SampleApp.Models
      @inject IOptions<MyOptions> optionsAccessor
      <p><b>Option1:</b> @optionsAccessor.Value.Option1</p>
      <p><b>Option2:</b> @optionsAccessor.Value.Option2</p>
      

      访问 MVC 视图文件中的配置

      以下代码显示 MVC 视图中的配置数据:

      @using Microsoft.Extensions.Configuration
      @inject IConfiguration Configuration
      Configuration value for 'MyKey': @Configuration["MyKey"]
      

      访问 Program.cs 中的配置

      以下代码访问 Program.cs 文件中的配置。

      var builder = WebApplication.CreateBuilder(args);
      var app = builder.Build();
      app.MapGet("/", () => "Hello World!");
      var key1 = app.Configuration.GetValue<int>("KeyOne");
      var key2 = app.Configuration.GetValue<bool>("KeyTwo");
      app.Logger.LogInformation($"KeyOne = {key1}");
      app.Logger.LogInformation($"KeyTwo = {key2}");
      app.Run();
      

      使用委托来配置选项

      在委托中配置的选项替代在配置提供程序中设置的值。

      在以下代码中,向服务容器添加了 IConfigureOptions<TOptions> 服务。 它使用委托来配置 MyOptions 的值:

      using SampleApp.Models;
      var builder = WebApplication.CreateBuilder(args);
      builder.Services.AddRazorPages();
      builder.Services.Configure<MyOptions>(myOptions =>
          myOptions.Option1 = "Value configured in delegate";
          myOptions.Option2 = 500;
      var app = builder.Build();
      

      以下代码显示选项值:

      public class Test2Model : PageModel
          private readonly IOptions<MyOptions> _optionsDelegate;
          public Test2Model(IOptions<MyOptions> optionsDelegate )
              _optionsDelegate = optionsDelegate;
          public ContentResult OnGet()
              return Content($"Option1: {_optionsDelegate.Value.Option1} \n" +
                             $"Option2: {_optionsDelegate.Value.Option2}");
      

      在前面的示例中,Option1Option2 的值在 appsettings.json 中指定,然后被配置的委托替代。

      主机与应用配置

      在配置并启动应用之前,配置并启动主机。 主机负责应用程序启动和生存期管理。 应用和主机均使用本主题中所述的配置提供程序进行配置。 应用的配置中也包含主机配置键值对。 有关在构建主机时如何使用配置提供程序,以及配置源如何影响主机配置的详细信息,请参阅 ASP.NET Core 基础知识概述

      默认主机配置

      有关使用 Web 主机时默认配置的详细信息,请参阅本主题的 ASP.NET Core 2.2 版本

    • 主机配置通过以下方式提供:
      • 使用环境变量配置提供程序通过前缀为 DOTNET_的环境变量(例如,DOTNET_ENVIRONMENT)提供。 在配置键值对加载后,前缀 (DOTNET_) 会遭去除。
      • 使用命令行配置提供程序通过命令行参数提供。
      • 已建立 Web 主机默认配置 (ConfigureWebHostDefaults):
        • Kestrel 用作 Web 服务器,并使用应用的配置提供程序对其进行配置。
        • 添加主机筛选中间件。
        • 如果 ASPNETCORE_FORWARDEDHEADERS_ENABLED 环境变量设置为 true,则添加转发的标头中间件。
        • 启用 IIS 集成。
        • 本主题仅与应用配置相关。 运行和托管 ASP.NET Core 应用的其他方面是使用本主题中未包含的配置文件进行配置:

        • launch.json/launchSettings.json 是用于开发环境的工具配置文件,如
          • 在 ASP.NET Core 中使用多个环境中。
          • 整个文档集中的文件用于为开发方案配置 ASP.NET Core 应用。
          • web.config 是服务器配置文件,如以下主题中所述:
            var builder = WebApplication.CreateBuilder(args);
            

            WebApplication.CreateBuilder 使用预配置的默认值初始化 类的新实例。 经过初始化的 WebApplicationBuilder (builder) 按照以下顺序为应用提供默认配置(从最高优先级到最低优先级):

          • 使用命令行配置提供程序通过命令行参数提供。
          • 使用非前缀环境变量配置提供程序通过非前缀环境变量提供。
          • 应用在 环境中运行时的用户机密
          • 使用 JSON 配置提供程序通过 appsettings.{Environment}.json 提供。 例如,appsettings.Production.jsonappsettings.Development.json
          • 使用 JSON 配置提供程序通过 appsettings.json 提供。
          • 回退到下一部分所述的主机配置。
          • 默认主机配置源

            以下列表包含从最高优先级到最低优先级的默认主机配置源:

          • 使用环境变量配置提供程序通过以 ASPNETCORE_ 为前缀的环境变量提供。
          • 使用命令行配置提供程序通过命令行参数提供
          • 使用环境变量配置提供程序通过以 DOTNET_ 为前缀的环境变量提供。
          • 在主机和应用程序配置中设置配置值时,将使用应用程序配置。

            请参阅此 GitHub 评论中的说明,了解说明在主机配置中以 ASPNETCORE_ 为前缀的环境变量的优先级高于命令行参数的原因。

            初始化主机生成器时,会提前锁定以下变量,并且它们不受应用程序配置的影响:

          • 应用程序名称
          • 环境名称,例如 DevelopmentProductionStaging
          • 内容根目录
          • Web 根目录
          • 是否要扫描托管启动程序集以及要扫描哪些程序集。
          • 应用和库代码从 IHostBuilder.ConfigureAppConfiguration 回调中的 HostBuilderContext.Configuration 读取的变量。
          • 从应用程序配置而不是主机配置读取所有其他主机设置。

            URLS 是许多不是启动设置的常见主机设置之一。 与不在前一个列表中的所有其他主机设置一样,稍后会从应用程序配置中读取 URLS。主机配置是应用程序配置的后备,因此主机配置可用于设置 URLS,但它将被应用程序配置中的任何配置源(如 appsettings.json)覆盖。

            有关详细信息,请参阅更改内容根、应用名称和环境通过环境变量或命令行更改内容根、应用名称和环境

            本文中的其余部分介绍应用程序配置。

            应用程序配置提供程序

            以下代码按添加顺序显示了已启用的配置提供程序:

            public class Index2Model : PageModel
                private IConfigurationRoot ConfigRoot;
                public Index2Model(IConfiguration configRoot)
                    ConfigRoot = (IConfigurationRoot)configRoot;
                public ContentResult OnGet()
                    string str = "";
                    foreach (var provider in ConfigRoot.Providers.ToList())
                        str += provider.ToString() + "\n";
                    return Content(str);
            

            前面的优先级从高到低的默认配置源列表以它们被添加到模板生成的应用程序中的相反顺序显示提供程序。 例如,JSON 配置提供程序被添加到命令行配置提供程序之前。

            后来添加的配置提供程序具有更高的优先级并且会替代之前的密钥设置。 例如,如果 appsettings.json 和环境中都设置了 MyKey,则使用环境值。 通过默认配置提供程序,命令行配置提供程序将替代其他所有提供程序。

            若要详细了解 CreateBuilder,请参阅默认生成器设置

            appsettings.json

            请考虑以下 appsettings.json 文件:

            "Position": { "Title": "Editor", "Name": "Joe Smith" "MyKey": "My appsettings.json Value", "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" "AllowedHosts": "*"

            以下来自示例下载的代码显示了上述的一些配置设置:

            public class TestModel : PageModel
                // requires using Microsoft.Extensions.Configuration;
                private readonly IConfiguration Configuration;
                public TestModel(IConfiguration configuration)
                    Configuration = configuration;
                public ContentResult OnGet()
                    var myKeyValue = Configuration["MyKey"];
                    var title = Configuration["Position:Title"];
                    var name = Configuration["Position:Name"];
                    var defaultLogLevel = Configuration["Logging:LogLevel:Default"];
                    return Content($"MyKey value: {myKeyValue} \n" +
                                   $"Title: {title} \n" +
                                   $"Name: {name} \n" +
                                   $"Default Log Level: {defaultLogLevel}");
            

            默认的 JsonConfigurationProvider 会按以下顺序加载配置:

          • appsettings.json
          • appsettings.{Environment}.json:例如,appsettings.Production.jsonappsettings.Development.json 文件。 文件的环境版本是根据 IHostingEnvironment.EnvironmentName 加载的。 有关详细信息,请参阅在 ASP.NET Core 中使用多个环境
          • appsettings.{Environment}.json 值替代 appsettings.json 中的键。 例如,默认情况下:

          • 在开发环境中,appsettings.Development.json 配置会覆盖在 appsettings.json 中找到的值。
          • 在生产环境中,appsettings.Production.json 配置会覆盖在 appsettings.json 中找到的值。 例如,在将应用部署到 Azure 时。
          • 如果必须保证配置值,请参阅 GetValue。 前面的示例只读取字符串,不支持默认值。

            使用默认配置时,会通过 reloadOnChange: true 启用 appsettings.jsonappsettings.{Environment}.json 文件。 应用启动后,对 appsettings.jsonappsettings.{Environment}.json 文件所做的更改将由 JSON 配置提供程序读取。

            使用选项模式绑定分层配置数据

            读取相关配置值的首选方法是使用选项模式。 例如,若要读取以下配置值,请执行以下操作:

              "Position": {
                "Title": "Editor",
                "Name": "Joe Smith"
            

            创建以下 PositionOptions 类:

            public class PositionOptions
                public const string Position = "Position";
                public string Title { get; set; } = String.Empty;
                public string Name { get; set; } = String.Empty;
            
          • 必须是包含公共无参数构造函数的非抽象类。
          • 类型的所有公共读写属性都已绑定。
          • 字段不是绑定的。 在上面的代码中,Position 未绑定。 由于使用了 Position 字段,因此在将类绑定到配置提供程序时,不需要在应用中对字符串 "Position" 进行硬编码。
          • 下面的代码:

          • 调用 ConfigurationBinder.Bind 类绑定到 Position 部分。
          • 显示 Position 配置数据。
          • public class Test22Model : PageModel
                private readonly IConfiguration Configuration;
                public Test22Model(IConfiguration configuration)
                    Configuration = configuration;
                public ContentResult OnGet()
                    var positionOptions = new PositionOptions();
                    Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);
                    return Content($"Title: {positionOptions.Title} \n" +
                                   $"Name: {positionOptions.Name}");
            

            在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。

            ConfigurationBinder.Get<T> 绑定并返回指定的类型。 使用 ConfigurationBinder.Get<T> 可能比使用 ConfigurationBinder.Bind 更方便。 下面的代码演示如何将 ConfigurationBinder.Get<T>PositionOptions 类配合使用:

            public class Test21Model : PageModel
                private readonly IConfiguration Configuration;
                public PositionOptions? positionOptions { get; private set; }
                public Test21Model(IConfiguration configuration)
                    Configuration = configuration;
                public ContentResult OnGet()
                    positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                                 .Get<PositionOptions>();
                    return Content($"Title: {positionOptions.Title} \n" +
                                   $"Name: {positionOptions.Name}");
            

            在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。

            使用选项模式时的另一种方法是绑定 Position 部分,并将其添加到依赖关系注入服务容器。 在以下代码中,PositionOptions 已通过 Configure 被添加到了服务容器并已绑定到了配置:

            using ConfigSample.Options;
            var builder = WebApplication.CreateBuilder(args);
            builder.Services.AddRazorPages();
            builder.Services.Configure<PositionOptions>(
                builder.Configuration.GetSection(PositionOptions.Position));
            var app = builder.Build();
            

            通过使用前面的代码,以下代码将读取位置选项:

            public class Test2Model : PageModel
                private readonly PositionOptions _options;
                public Test2Model(IOptions<PositionOptions> options)
                    _options = options.Value;
                public ContentResult OnGet()
                    return Content($"Title: {_options.Title} \n" +
                                   $"Name: {_options.Name}");
            

            在上面的代码中,不会读取在应用启动后对 JSON 配置文件所做的更改。 若要读取在应用启动后的更改,请使用 IOptionsSnapshot

            使用默认配置时,会通过 reloadOnChange: true 启用 appsettings.jsonappsettings.{Environment}.json 文件。 应用启动后,对 appsettings.jsonappsettings.{Environment}.json 文件所做的更改将由 JSON 配置提供程序读取。

            有关添加其他 JSON 配置文件的信息,请参阅本文档中的 JSON 配置提供程序

            合并服务集合

            考虑下面的方法,该方法可注册服务并配置选项:

            using ConfigSample.Options;
            using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
            var builder = WebApplication.CreateBuilder(args);
            builder.Services.AddRazorPages();
            builder.Services.Configure<PositionOptions>(
                builder.Configuration.GetSection(PositionOptions.Position));
            builder.Services.Configure<ColorOptions>(
                builder.Configuration.GetSection(ColorOptions.Color));
            builder.Services.AddScoped<IMyDependency, MyDependency>();
            builder.Services.AddScoped<IMyDependency2, MyDependency2>();
            var app = builder.Build();
            

            可以将相关的注册组移动到扩展方法以注册服务。 例如,配置服务会被添加到以下类中:

            using ConfigSample.Options;
            using Microsoft.Extensions.Configuration;
            namespace Microsoft.Extensions.DependencyInjection
                public static class MyConfigServiceCollectionExtensions
                    public static IServiceCollection AddConfig(
                         this IServiceCollection services, IConfiguration config)
                        services.Configure<PositionOptions>(
                            config.GetSection(PositionOptions.Position));
                        services.Configure<ColorOptions>(
                            config.GetSection(ColorOptions.Color));
                        return services;
                    public static IServiceCollection AddMyDependencyGroup(
                         this IServiceCollection services)
                        services.AddScoped<IMyDependency, MyDependency>();
                        services.AddScoped<IMyDependency2, MyDependency2>();
                        return services;
            

            剩余的服务会在类似的类中注册。 下面的代码使用新扩展方法来注册服务:

            using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
            var builder = WebApplication.CreateBuilder(args);
            builder.Services
                .AddConfig(builder.Configuration)
                .AddMyDependencyGroup();
            builder.Services.AddRazorPages();
            var app = builder.Build();
            

            注意:每个 services.Add{GROUP_NAME} 扩展方法添加并可能配置服务。 例如,AddControllersWithViews 会添加带视图的 MVC 控制器所需的服务,AddRazorPages 会添加 Razor Pages 所需的服务。

            安全性和用户机密

            配置数据指南:

          • 请勿在配置提供程序代码或纯文本配置文件中存储密码或其他敏感数据。 机密管理器工具可用于存储开发环境中的机密。
          • 不要在开发或测试环境中使用生产机密。
          • 请在项目外部指定机密,避免将其意外提交到源代码存储库。
          • 默认情况下,将在 JSON 配置源后注册用户机密配置源。 因此,用户机密密钥优先于 appsettings.jsonappsettings.{Environment}.json 中的密钥。

            有关存储密码或其他敏感数据的详细信息:

          • 在 ASP.NET Core 中使用多个环境
          • 在 ASP.NET Core 开发环境中安全存储应用机密:包括有关使用环境变量存储敏感数据的建议。 机密管理器工具使用文件配置提供程序将用户机密存储在本地系统上的 JSON 文件中。
          • Azure Key Vault 安全存储 ASP.NET Core 应用的应用机密。 有关详细信息,请参阅 ASP.NET Core 中的 Azure Key Vault 配置提供程序

            非前缀环境变量

            非前缀环境变量不是以ASPNETCORE_DOTNET_ 为前缀的环境变量。 例如,launchSettings.json 中的 ASP.NET Core Web 应用程序模板设置集 "ASPNETCORE_ENVIRONMENT": "Development"。 有关 ASPNETCORE_DOTNET_ 环境变量的详细信息,请参阅以下内容:

          • 最高到最低优先级的默认配置源列表,包括非前缀、以 ASPNETCORE_ 为前缀和以 DOTNETCORE_ 为前缀的环境变量。
          • Microsoft.Extensions.Hosting 外部使用的 DOTNET_ 环境变量。
          • 使用默认配置时,EnvironmentVariablesConfigurationProvider 会在读取 appsettings.jsonappsettings.{Environment}.json用户机密之后,从环境变量键值对中加载配置。 因此,从环境中读取的键值会替代从 appsettings.jsonappsettings.{Environment}.json 和用户机密中读取的值。

            所有平台上的环境变量分层键都不支持 : 分隔符。 __(双下划线):

          • 受所有平台支持。 例如,Bash 不支持 : 分隔符,但支持 __
          • 自动替换为 :
          • 以下 set 命令:

          • 在 Windows 上设置上述示例的环境键和值。
          • 在使用示例下载时测试设置。 dotnet run 命令必须在项目目录中运行。
          • set MyKey="My key from Environment"
            set Position__Title=Environment_Editor
            set Position__Name=Environment_Rick
            dotnet run
            

            前面的环境设置:

          • 仅在进程中设置,这些进程是从设置进程的命令窗口启动的。
          • 不会由通过 Visual Studio 启动的浏览器读取。
          • 以下 setx 命令可用于在 Windows 上设置环境键和值。 与 set 不同,setx 设置是持久的。 /M 在系统环境中设置变量。 如果未使用 /M 开关,则会设置用户环境变量。

            setx MyKey "My key from setx Environment" /M
            setx Position__Title Environment_Editor /M
            setx Position__Name Environment_Rick /M
            

            测试前面的命令是否会替代 appsettings.jsonappsettings.{Environment}.json

          • 使用 Visual Studio:退出并重启 Visual Studio。
          • 使用 CLI:启动新的命令窗口并输入 dotnet run
          • 使用字符串调用 AddEnvironmentVariables 以指定环境变量的前缀:

            var builder = WebApplication.CreateBuilder(args);
            builder.Services.AddRazorPages();
            builder.Configuration.AddEnvironmentVariables(prefix: "MyCustomPrefix_");
            var app = builder.Build();
            

            在上述代码中:

          • builder.Configuration.AddEnvironmentVariables(prefix: "MyCustomPrefix_") 被添加到默认配置提供程序之后。 有关对配置提供程序进行排序的示例,请参阅 JSON 配置提供程序
          • 使用 MyCustomPrefix_ 前缀设置的环境变量将替代默认配置提供程序。 这包括没有前缀的环境变量。
          • 前缀会在读取配置键值对时被去除。

            以下命令对自定义前缀进行测试:

            set MyCustomPrefix_MyKey="My key with MyCustomPrefix_ Environment"
            set MyCustomPrefix_Position__Title=Editor_with_customPrefix
            set MyCustomPrefix_Position__Name=Environment_Rick_cp
            dotnet run
            

            默认配置会加载前缀为 DOTNET_ASPNETCORE_ 的环境变量和命令行参数。 DOTNET_ASPNETCORE_ 前缀会由 ASP.NET Core 用于主机和应用配置,但不用于用户配置。 有关主机和应用配置的详细信息,请参阅 .NET 通用主机

            Azure 应用服务上,选择“设置”>“配置”页面上的“新应用程序设置”。 Azure 应用服务应用程序设置:

          • 已静态加密且通过加密的通道进行传输。
          • 已作为环境变量公开。
          • 有关详细信息,请参阅 Azure 应用:使用 Azure 门户替代应用配置

            有关 Azure 数据库连接字符串的信息,请参阅连接字符串前缀

            环境变量的命名

            环境变量名称反映了 appsettings.json 文件的结构。 层次结构中的每个元素由双下划线字符(更可取)或冒号分隔。 当元素结构包含数组时,应将数组索引视为此路径中的附加元素名称。 请考虑以下 appsettings.json 文件及其表示为环境变量的等效值。

            appsettings.json

            "SmtpServer": "smtp.example.com", "Logging": [ "Name": "ToEmail", "Level": "Critical", "Args": { "FromAddress": "MySystem@example.com", "ToAddress": "SRE@example.com" "Name": "ToConsole", "Level": "Information"
            setx SmtpServer smtp.example.com
            setx Logging__0__Name ToEmail
            setx Logging__0__Level Critical
            setx Logging__0__Args__FromAddress MySystem@example.com
            setx Logging__0__Args__ToAddress SRE@example.com
            setx Logging__1__Name ToConsole
            setx Logging__1__Level Information
            

            在生成的 launchSettings.json 中设置的环境变量

            launchSettings.json 中设置的环境变量将替代在系统环境中设置的变量。 例如,ASP.NET Core Web 模板会生成一个 launchSettings.json 文件,该文件将终结点配置设置为:

            "applicationUrl": "https://localhost:5001;http://localhost:5000"
            

            配置 applicationUrl 将设置 ASPNETCORE_URLS 环境变量并重写环境中设置的值。

            在 Linux 上转义环境变量

            在 Linux 上,必须转义 URL 环境变量的值,使 systemd 可以对其进行分析。 使用 Linux 工具 systemd-escape 生成 http:--localhost:5001

            groot@terminus:~$ systemd-escape http://localhost:5001
            http:--localhost:5001
            

            显示环境变量

            下面的代码显示了应用程序启动时的环境变量和值,这对调试环境设置很有帮助:

            var builder = WebApplication.CreateBuilder(args);
            var app = builder.Build();
            foreach (var c in builder.Configuration.AsEnumerable())
                Console.WriteLine(c.Key + " = " + c.Value);
            

            使用默认配置,CommandLineConfigurationProvider 会从以下配置源后的命令行参数键值对中加载配置:

          • appsettings.jsonappsettings.{Environment}.json 文件。
          • 开发环境中的应用机密
          • 环境变量。
          • 默认情况下,在命令行上设置的配置值会替代通过所有其他配置提供程序设置的配置值。

            命令行参数

            以下命令使用 = 设置键和值:

            dotnet run MyKey="Using =" Position:Title=Cmd Position:Name=Cmd_Rick
            

            以下命令使用 / 设置键和值:

            dotnet run /MyKey "Using /" /Position:Title=Cmd /Position:Name=Cmd_Rick
            

            以下命令使用 -- 设置键和值:

            dotnet run --MyKey "Using --" --Position:Title=Cmd --Position:Name=Cmd_Rick
            
          • 必须后跟 =,或者当值后跟一个空格时,键必须具有一个 --/ 的前缀。
          • 如果使用 =,则不是必需的。 例如 MySetting=
          • 在同一命令中,请勿将使用 = 的命令行参数键值对与使用空格的键值对混合使用。

            交换映射支持键名替换逻辑。 提供针对 AddCommandLine 方法的交换替换字典。

            当使用交换映射字典时,会检查字典中是否有与命令行参数提供的键匹配的键。 如果在字典中找到了命令行键,则会传回字典值将键值对设置为应用的配置。 对任何具有单划线 (-) 前缀的命令行键而言,交换映射都是必需的。

            交换映射字典键规则:

          • 交换必须以 --- 开头。
          • 交换映射字典不得包含重复键。
          • 若要使用交换映射字典,请将它传递到对 AddCommandLine 的调用中:

            var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorPages(); var switchMappings = new Dictionary<string, string>() { "-k1", "key1" }, { "-k2", "key2" }, { "--alt3", "key3" }, { "--alt4", "key4" }, { "--alt5", "key5" }, { "--alt6", "key6" }, builder.Configuration.AddCommandLine(args, switchMappings); var app = builder.Build();

            运行以下命令可测试键替换:

            dotnet run -k1 value1 -k2 value2 --alt3=value2 /alt4=value3 --alt5 value5 /alt6 value6
            

            下面的代码显示了替换后的键的键值:

            public class Test3Model : PageModel
                private readonly IConfiguration Config;
                public Test3Model(IConfiguration configuration)
                    Config = configuration;
                public ContentResult OnGet()
                    return Content(
                            $"Key1: '{Config["Key1"]}'\n" +
                            $"Key2: '{Config["Key2"]}'\n" +
                            $"Key3: '{Config["Key3"]}'\n" +
                            $"Key4: '{Config["Key4"]}'\n" +
                            $"Key5: '{Config["Key5"]}'\n" +
                            $"Key6: '{Config["Key6"]}'");
            

            对于使用交换映射的应用,调用 CreateDefaultBuilder 不应传递参数。 CreateDefaultBuilder 方法的 AddCommandLine 调用不包括映射的交换,并且无法将交换映射字典传递给 CreateDefaultBuilder。 解决方案不是将参数传递给 CreateDefaultBuilder,而是允许 ConfigurationBuilder 方法的 AddCommandLine 方法处理参数和交换映射字典。

            在 Visual Studio 中设置环境和命令行参数

            可以在 Visual Studio 中的“启动配置文件”对话框设置环境和命令行参数:

          • 在“解决方案资源管理器”中,右键单击项目,然后选择“属性”。
          • 转到“调试”>“常规”选项卡,然后选择“打开调试启动配置文件 UI”>
          • 分层配置数据

            配置 API 在配置键中使用分隔符来展平分层数据,以此来读取分层配置数据。

            示例下载包含以下 appsettings.json 文件:

            "Position": { "Title": "Editor", "Name": "Joe Smith" "MyKey": "My appsettings.json Value", "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" "AllowedHosts": "*"

            以下来自示例下载的代码显示了一些配置设置:

            public class TestModel : PageModel
                // requires using Microsoft.Extensions.Configuration;
                private readonly IConfiguration Configuration;
                public TestModel(IConfiguration configuration)
                    Configuration = configuration;
                public ContentResult OnGet()
                    var myKeyValue = Configuration["MyKey"];
                    var title = Configuration["Position:Title"];
                    var name = Configuration["Position:Name"];
                    var defaultLogLevel = Configuration["Logging:LogLevel:Default"];
                    return Content($"MyKey value: {myKeyValue} \n" +
                                   $"Title: {title} \n" +
                                   $"Name: {name} \n" +
                                   $"Default Log Level: {defaultLogLevel}");
            

            读取分层配置数据的首选方法是使用选项模式。 有关详细信息,请参阅本文档中的绑定分层配置数据

            GetSectionGetChildren 方法可用于隔离各个节和配置数据中某节的子节。 稍后将在 GetSection、GetChildren 和 Exists 中介绍这些方法。

            配置键和值

          • 不区分大小写。 例如,ConnectionStringconnectionstring 被视为等效键。
          • 如果在多个配置提供程序中设置了某一键和值,则会使用最后添加的提供程序中的值。 有关详细信息,请参阅默认配置
          • 在配置 API 中,冒号分隔符 (:) 适用于所有平台。
          • 在环境变量中,冒号分隔符可能无法适用于所有平台。 所有平台均支持采用双下划线 __,并且它会自动转换为冒号 :
          • 在 Azure Key Vault 中,分层键使用 -- 作为分隔符。 当机密加载到应用的配置中时,Azure Key Vault 配置提供程序 会自动将 -- 替换为 :
          • ConfigurationBinder 支持使用配置键中的数组索引将数组绑定到对象。 数组绑定将在将数组绑定到类部分中进行介绍。
          • 为字符串。
          • NULL 值不能存储在配置中或绑定到对象。
          • 配置提供程序

            下表显示了 ASP.NET Core 应用可用的配置提供程序。

            通过以下对象提供配置 MYSQLCONNSTR_{KEY} ConnectionStrings:{KEY} 键:ConnectionStrings:{KEY}_ProviderName
            值:MySql.Data.MySqlClient SQLAZURECONNSTR_{KEY} ConnectionStrings:{KEY} 键:ConnectionStrings:{KEY}_ProviderName
            值:System.Data.SqlClient SQLCONNSTR_{KEY} ConnectionStrings:{KEY} 键:ConnectionStrings:{KEY}_ProviderName
            值:System.Data.SqlClient

            FileConfigurationProvider 是从文件系统加载配置的基类。 以下配置提供程序派生自 FileConfigurationProvider

          • INI 配置提供程序
          • JSON 配置提供程序
          • XML 配置提供程序
          • INI 配置提供程序

            IniConfigurationProvider 在运行时从 INI 文件键值对加载配置。

            以下代码添加多个配置提供程序:

            var builder = WebApplication.CreateBuilder(args);
            builder.Configuration
                .AddIniFile("MyIniConfig.ini", optional: true, reloadOnChange: true)
                .AddIniFile($"MyIniConfig.{builder.Environment.EnvironmentName}.ini",
                            optional: true, reloadOnChange: true);
            builder.Configuration.AddEnvironmentVariables();
            builder.Configuration.AddCommandLine(args);
            builder.Services.AddRazorPages();
            var app = builder.Build();
            

            在前面的代码中,MyIniConfig.iniMyIniConfig.{Environment}.ini 文件中的设置会被以下提供程序中的设置替代:

          • 环境变量配置提供程序
          • 命令行配置提供程序
          • 示例下载包含以下 MyIniConfig.ini 文件:

            MyKey="MyIniConfig.ini Value"
            [Position]
            Title="My INI Config title"
            Name="My INI Config name"
            [Logging:LogLevel]
            Default=Information
            Microsoft=Warning
            

            以下来自示例下载的代码显示了上述的一些配置设置:

            public class TestModel : PageModel
                // requires using Microsoft.Extensions.Configuration;
                private readonly IConfiguration Configuration;
                public TestModel(IConfiguration configuration)
                    Configuration = configuration;
                public ContentResult OnGet()
                    var myKeyValue = Configuration["MyKey"];
                    var title = Configuration["Position:Title"];
                    var name = Configuration["Position:Name"];
                    var defaultLogLevel = Configuration["Logging:LogLevel:Default"];
                    return Content($"MyKey value: {myKeyValue} \n" +
                                   $"Title: {title} \n" +
                                   $"Name: {name} \n" +
                                   $"Default Log Level: {defaultLogLevel}");
            

            JSON 配置提供程序

            JsonConfigurationProvider 从 JSON 文件键值对加载配置。

            重载可以指定:

          • 文件是否可选。
          • 如果文件更改,是否重载配置。
          • 考虑下列代码:

            using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
            var builder = WebApplication.CreateBuilder(args);
            builder.Configuration.AddJsonFile("MyConfig.json",
                    optional: true,
                    reloadOnChange: true);
            builder.Services.AddRazorPages();
            var app = builder.Build();
            

            前面的代码:

          • 通过以下选项将 JSON 配置提供程序配置为加载 MyConfig.json 文件:
            • optional: true:文件是可选的。
            • reloadOnChange: true:保存更改后会重载文件。
            • 读取 MyConfig.json 文件之前的默认配置提供程序MyConfig.json 文件中的设置会替代默认配置提供程序中的设置,包括环境变量配置提供程序命令行配置提供程序
            • 通常,你不会希望自定义 JSON 文件替代在环境变量配置提供程序命令行配置提供程序中设置的值

              XML 配置提供程序

              XmlConfigurationProvider 在运行时从 XML 文件键值对加载配置。

              以下代码添加多个配置提供程序:

              var builder = WebApplication.CreateBuilder(args);
              builder.Configuration
                  .AddXmlFile("MyXMLFile.xml", optional: true, reloadOnChange: true)
                  .AddXmlFile($"MyXMLFile.{builder.Environment.EnvironmentName}.xml",
                              optional: true, reloadOnChange: true);
              builder.Configuration.AddEnvironmentVariables();
              builder.Configuration.AddCommandLine(args);
              builder.Services.AddRazorPages();
              var app = builder.Build();
              

              在前面的代码中,MyXMLFile.xmlMyXMLFile.{Environment}.xml 文件中的设置会被以下提供程序中的设置替代:

            • 环境变量配置提供程序
            • 命令行配置提供程序
            • 示例下载包含以下 MyXMLFile.xml 文件:

              <?xml version="1.0" encoding="utf-8" ?>
              <configuration>
                <MyKey>MyXMLFile Value</MyKey>
                <Position>
                  <Title>Title from  MyXMLFile</Title>
                  <Name>Name from MyXMLFile</Name>
                </Position>
                <Logging>
                  <LogLevel>
                    <Default>Information</Default>
                    <Microsoft>Warning</Microsoft>
                  </LogLevel>
                </Logging>
              </configuration>
              

              以下来自示例下载的代码显示了上述的一些配置设置:

              public class TestModel : PageModel
                  // requires using Microsoft.Extensions.Configuration;
                  private readonly IConfiguration Configuration;
                  public TestModel(IConfiguration configuration)
                      Configuration = configuration;
                  public ContentResult OnGet()
                      var myKeyValue = Configuration["MyKey"];
                      var title = Configuration["Position:Title"];
                      var name = Configuration["Position:Name"];
                      var defaultLogLevel = Configuration["Logging:LogLevel:Default"];
                      return Content($"MyKey value: {myKeyValue} \n" +
                                     $"Title: {title} \n" +
                                     $"Name: {name} \n" +
                                     $"Default Log Level: {defaultLogLevel}");
              

              如果使用 name 属性来区分元素,则使用相同元素名称的重复元素可以正常工作:

              <?xml version="1.0" encoding="UTF-8"?>
              <configuration>
                <section name="section0">
                  <key name="key0">value 00</key>
                  <key name="key1">value 01</key>
                </section>
                <section name="section1">
                  <key name="key0">value 10</key>
                  <key name="key1">value 11</key>
                </section>
              </configuration>
              

              以下代码会读取前面的配置文件并显示键和值:

              public class IndexModel : PageModel
                  private readonly IConfiguration Configuration;
                  public IndexModel(IConfiguration configuration)
                      Configuration = configuration;
                  public ContentResult OnGet()
                      var key00 = "section:section0:key:key0";
                      var key01 = "section:section0:key:key1";
                      var key10 = "section:section1:key:key0";
                      var key11 = "section:section1:key:key1";
                      var val00 = Configuration[key00];
                      var val01 = Configuration[key01];
                      var val10 = Configuration[key10];
                      var val11 = Configuration[key11];
                      return Content($"{key00} value: {val00} \n" +
                                     $"{key01} value: {val01} \n" +
                                     $"{key10} value: {val10} \n" +
                                     $"{key10} value: {val11} \n"
              

              属性可用于提供值:

              <?xml version="1.0" encoding="UTF-8"?>
              <configuration>
                <key attribute="value" />
                <section>
                  <key attribute="value" />
                </section>
              </configuration>
              

              以前的配置文件使用 value 加载以下键:

            • key:attribute
            • section:key:attribute
            • Key-per-file 配置提供程序

              KeyPerFileConfigurationProvider 使用目录的文件作为配置键值对。 该键是文件名。 该值包含文件的内容。 Key-per-file 配置提供程序用于 Docker 托管方案。

              若要激活 Key-per-file 配置,请在 ConfigurationBuilder 的实例上调用 AddKeyPerFile 扩展方法。 文件的 directoryPath 必须是绝对路径。

              重载允许指定:

            • 配置源的 Action<KeyPerFileConfigurationSource> 委托。
            • 目录是否可选以及目录的路径。
            • 双下划线字符 (__) 用作文件名中的配置键分隔符。 例如,文件名 Logging__LogLevel__System 生成配置键 Logging:LogLevel:System

              构建主机时调用 ConfigureAppConfiguration 以指定应用的配置:

              .ConfigureAppConfiguration((hostingContext, config) =>
                  var path = Path.Combine(
                      Directory.GetCurrentDirectory(), "path/to/files");
                  config.AddKeyPerFile(directoryPath: path, optional: true);
              

              内存配置提供程序

              MemoryConfigurationProvider 使用内存中集合作为配置键值对。

              以下代码将内存集合添加到配置系统中:

              var builder = WebApplication.CreateBuilder(args);
              var Dict = new Dictionary<string, string>
                         {"MyKey", "Dictionary MyKey Value"},
                         {"Position:Title", "Dictionary_Title"},
                         {"Position:Name", "Dictionary_Name" },
                         {"Logging:LogLevel:Default", "Warning"}
              builder.Configuration.AddInMemoryCollection(Dict);
              builder.Configuration.AddEnvironmentVariables();
              builder.Configuration.AddCommandLine(args);
              builder.Services.AddRazorPages();
              var app = builder.Build();
              

              以下来自示例下载的代码显示了上述配置设置:

              public class TestModel : PageModel
                  // requires using Microsoft.Extensions.Configuration;
                  private readonly IConfiguration Configuration;
                  public TestModel(IConfiguration configuration)
                      Configuration = configuration;
                  public ContentResult OnGet()
                      var myKeyValue = Configuration["MyKey"];
                      var title = Configuration["Position:Title"];
                      var name = Configuration["Position:Name"];
                      var defaultLogLevel = Configuration["Logging:LogLevel:Default"];
                      return Content($"MyKey value: {myKeyValue} \n" +
                                     $"Title: {title} \n" +
                                     $"Name: {name} \n" +
                                     $"Default Log Level: {defaultLogLevel}");
              

              在前面的代码中,config.AddInMemoryCollection(Dict) 会被添加到默认配置提供程序之后。 有关对配置提供程序进行排序的示例,请参阅 JSON 配置提供程序

              有关使用 MemoryConfigurationProvider 的其他示例,请参阅绑定数组

              Kestrel 终结点配置

              Kestrel 特定的终结点配置将覆盖所有跨服务器终结点配置。 跨服务器终结点配置包括:

            • UseUrls
            • 命令行上的 --urls
            • 环境变量ASPNETCORE_URLS
            • 请考虑在 ASP.NET Core Web 应用中使用的以下 appsettings.json 文件:

              "Kestrel": { "Endpoints": { "Https": { "Url": "https://localhost:9999" "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" "AllowedHosts": "*"

              当在 ASP.NET Core Web 应用中使用前面突出显示的标记,并且应用在命令行上启动,且跨服务器端点配置如下时

              dotnet run --urls="https://localhost:7777"

              Kestrel 将绑定到专门针对 appsettings.json 文件中的 Kestrel 配置的终结点 (https://localhost:9999),而不是 https://localhost:7777

              请考虑将 Kestrel 特定的终结点配置为环境变量:

              set Kestrel__Endpoints__Https__Url=https://localhost:8888

              在前面的环境变量中,Https 是 Kestrel 特定的终结点的名称。 前面的 appsettings.json 文件还定义了名为 Https 的 Kestrel 特定终结点。 默认情况下,将在 appsettings.{Environment}.json 后读取使用环境变量配置提供程序的环境变量,因此,前面的环境变量用于 Https 终结点。

              GetValue

              ConfigurationBinder.GetValue 从配置中提取一个具有指定键的值,并将它转换为指定的类型:

              public class TestNumModel : PageModel
                  private readonly IConfiguration Configuration;
                  public TestNumModel(IConfiguration configuration)
                      Configuration = configuration;
                  public ContentResult OnGet()
                      var number = Configuration.GetValue<int>("NumberKey", 99);
                      return Content($"{number}");
              

              在前面的代码中,如果在配置中找不到 NumberKey,则使用默认值 99

              GetSection、GetChildren 和 Exists

              对于下面的示例,请考虑以下 MySubsection.json 文件:

              "section0": { "key0": "value00", "key1": "value01" "section1": { "key0": "value10", "key1": "value11" "section2": { "subsection0": { "key0": "value200", "key1": "value201" "subsection1": { "key0": "value210", "key1": "value211"

              以下代码将 MySubsection.json 添加到配置提供程序:

              var builder = WebApplication.CreateBuilder(args);
              builder.Configuration
                  .AddJsonFile("MySubsection.json",
                               optional: true,
                               reloadOnChange: true);
              builder.Services.AddRazorPages();
              var app = builder.Build();
              

              GetSection

              IConfiguration.GetSection 会返回具有指定子节键的配置子节。

              以下代码将返回 section1 的值:

              public class TestSectionModel : PageModel
                  private readonly IConfiguration Config;
                  public TestSectionModel(IConfiguration configuration)
                      Config = configuration.GetSection("section1");
                  public ContentResult OnGet()
                      return Content(
                              $"section1:key0: '{Config["key0"]}'\n" +
                              $"section1:key1: '{Config["key1"]}'");
              

              以下代码将返回 section2:subsection0 的值:

              public class TestSection2Model : PageModel
                  private readonly IConfiguration Config;
                  public TestSection2Model(IConfiguration configuration)
                      Config = configuration.GetSection("section2:subsection0");
                  public ContentResult OnGet()
                      return Content(
                              $"section2:subsection0:key0 '{Config["key0"]}'\n" +
                              $"section2:subsection0:key1:'{Config["key1"]}'");
              

              GetSection 永远不会返回 null。 如果找不到匹配的节,则返回空 IConfigurationSection

              GetSection 返回匹配的部分时,Value 未填充。 存在该部分时,返回一个 KeyPath 部分。

              GetChildren 和 Exists

              以下代码将调用 IConfiguration.GetChildren 并返回 section2:subsection0 的值:

              public class TestSection4Model : PageModel
                  private readonly IConfiguration Config;
                  public TestSection4Model(IConfiguration configuration)
                      Config = configuration;
                  public ContentResult OnGet()
                      string s = "";
                      var selection = Config.GetSection("section2");
                      if (!selection.Exists())
                          throw new Exception("section2 does not exist.");
                      var children = selection.GetChildren();
                      foreach (var subSection in children)
                          int i = 0;
                          var key1 = subSection.Key + ":key" + i++.ToString();
                          var key2 = subSection.Key + ":key" + i.ToString();
                          s += key1 + " value: " + selection[key1] + "\n";
                          s += key2 + " value: " + selection[key2] + "\n";
                      return Content(s);
              

              前面的代码将调用 ConfigurationExtensions.Exists 以验证该节是否存在:

              ConfigurationBinder.Bind 支持使用配置键中的数组索引将数组绑定到对象。 公开数值键段的任何数组格式都能够与 POCO 类数组进行数组绑定。

              请考虑示例下载中的 MyArray.json

              "array": { "entries": { "0": "value00", "1": "value10", "2": "value20", "4": "value40", "5": "value50"

              以下代码将 MyArray.json 添加到配置提供程序:

              var builder = WebApplication.CreateBuilder(args);
              builder.Configuration
                  .AddJsonFile("MyArray.json",
                               optional: true,
                               reloadOnChange: true);
              builder.Services.AddRazorPages();
              var app = builder.Build();
              

              以下代码将读取配置并显示值:

              public class ArrayModel : PageModel
                  private readonly IConfiguration Config;
                  public ArrayExample? _array { get; private set; }
                  public ArrayModel(IConfiguration config)
                      Config = config;
                  public ContentResult OnGet()
                     _array = Config.GetSection("array").Get<ArrayExample>();
                      if (_array == null)
                          throw new ArgumentNullException(nameof(_array));
                      string s = String.Empty;
                      for (int j = 0; j < _array.Entries.Length; j++)
                          s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
                      return Content(s);
              
              public class ArrayExample
                  public string[]? Entries { get; set; } 
              

              前面的代码会返回以下输出:

              Index: 0  Value: value00
              Index: 1  Value: value10
              Index: 2  Value: value20
              Index: 3  Value: value40
              Index: 4  Value: value50
              

              在前面的输出中,索引 3 具有值 value40,与 MyArray.json 中的 "4": "value40", 相对应。 绑定的数组索引是连续的,并且未绑定到配置键索引。 配置绑定器不能绑定 NULL 值,也不能在绑定的对象中创建 NULL 条目。

              自定义配置提供程序

              该示例应用演示了如何使用实体框架 (EF) 创建从数据库读取配置键值对的基本配置提供程序。

              提供程序具有以下特征:

            • EF 内存中数据库用于演示目的。 若要使用需要连接字符串的数据库,请实现辅助 ConfigurationBuilder 以从另一个配置提供程序提供连接字符串。
            • 提供程序在启动时将数据库表读入配置。 提供程序不会基于每个键查询数据库。
            • 未实现更改时重载,因此在应用启动后更新数据库对应用的配置没有任何影响。
            • 定义用于在数据库中存储配置值的 EFConfigurationValue 实体。

              Models/EFConfigurationValue.cs:

              public class EFConfigurationValue
                  public string Id { get; set; } = String.Empty;
                  public string Value { get; set; } = String.Empty;
              

              添加 EFConfigurationContext 以存储和访问配置的值。

              EFConfigurationProvider/EFConfigurationContext.cs:

              public class EFConfigurationContext : DbContext
                  public EFConfigurationContext(DbContextOptions<EFConfigurationContext> options) : base(options)
                  public DbSet<EFConfigurationValue> Values => Set<EFConfigurationValue>();
              

              创建用于实现 IConfigurationSource 的类。

              EFConfigurationProvider/EFConfigurationSource.cs:

              public class EFConfigurationSource : IConfigurationSource
                  private readonly Action<DbContextOptionsBuilder> _optionsAction;
                  public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction) => _optionsAction = optionsAction;
                  public IConfigurationProvider Build(IConfigurationBuilder builder) => new EFConfigurationProvider(_optionsAction);
              

              通过从 ConfigurationProvider 继承来创建自定义配置提供程序。 当数据库为空时,配置提供程序将对其进行初始化。 由于配置密钥不区分大小写,因此用来初始化数据库的字典是用不区分大小写的比较程序 (StringComparer.OrdinalIgnoreCase) 创建的。

              EFConfigurationProvider/EFConfigurationProvider.cs:

              public class EFConfigurationProvider : ConfigurationProvider
                  public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
                      OptionsAction = optionsAction;
                  Action<DbContextOptionsBuilder> OptionsAction { get; }
                  public override void Load()
                      var builder = new DbContextOptionsBuilder<EFConfigurationContext>();
                      OptionsAction(builder);
                      using (var dbContext = new EFConfigurationContext(builder.Options))
                          if (dbContext == null || dbContext.Values == null)
                              throw new Exception("Null DB context");
                          dbContext.Database.EnsureCreated();
                          Data = !dbContext.Values.Any()
                              ? CreateAndSaveDefaultValues(dbContext)
                              : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
                  private static IDictionary<string, string> CreateAndSaveDefaultValues(
                      EFConfigurationContext dbContext)
                      // Quotes (c)2005 Universal Pictures: Serenity
                      // https://www.uphe.com/movies/serenity-2005
                      var configValues =
                          new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
                                  { "quote1", "I aim to misbehave." },
                                  { "quote2", "I swallowed a bug." },
                                  { "quote3", "You can't stop the signal, Mal." }
                      if (dbContext == null || dbContext.Values == null)
                          throw new Exception("Null DB context");
                      dbContext.Values.AddRange(configValues
                          .Select(kvp => new EFConfigurationValue
                              Id = kvp.Key,
                              Value = kvp.Value
                          .ToArray());
                      dbContext.SaveChanges();
                      return configValues;
              

              可以使用 AddEFConfiguration 扩展方法将配置源添加到 ConfigurationBuilder

              Extensions/EntityFrameworkExtensions.cs:

              public static class EntityFrameworkExtensions
                  public static IConfigurationBuilder AddEFConfiguration(
                             this IConfigurationBuilder builder,
                             Action<DbContextOptionsBuilder> optionsAction)
                      return builder.Add(new EFConfigurationSource(optionsAction));
              

              下面的代码演示如何在 Program.cs 中使用自定义的 EFConfigurationProvider

              //using Microsoft.EntityFrameworkCore;
              var builder = WebApplication.CreateBuilder(args);
              builder.Configuration.AddEFConfiguration(
                  opt => opt.UseInMemoryDatabase("InMemoryDb"));
              var app = builder.Build();
              app.Run();
              

              使用依赖关系注入 (DI) 的访问配置

              通过解析 IConfiguration 服务,可以使用依赖关系注入 (DI) 将配置注入服务:

              public class Service
                  private readonly IConfiguration _config;
                  public Service(IConfiguration config) =>
                      _config = config;
                  public void DoSomething()
                      var configSettingValue = _config["ConfigSetting"];
                      // ...
              

              有关如何使用 IConfiguration 访问值的信息,请参阅本文中的 GetValue 以及 GetSection、GetChildren 和 Exists

              访问 Razor Pages 中的配置

              以下代码显示 Razor Pages 中的配置数据:

              @page
              @model Test5Model
              @using Microsoft.Extensions.Configuration
              @inject IConfiguration Configuration
              Configuration value for 'MyKey': @Configuration["MyKey"]
              

              在以下代码中,MyOptions 已通过 Configure 被添加到了服务容器并已绑定到了配置:

              using SampleApp.Models;
              var builder = WebApplication.CreateBuilder(args);
              builder.Services.AddRazorPages();
              builder.Services.Configure<MyOptions>(
                  builder.Configuration.GetSection("MyOptions"));
              var app = builder.Build();
              

              以下标记使用 @injectRazor 指令来解析和显示选项值:

              @page
              @model SampleApp.Pages.Test3Model
              @using Microsoft.Extensions.Options
              @using SampleApp.Models
              @inject IOptions<MyOptions> optionsAccessor
              <p><b>Option1:</b> @optionsAccessor.Value.Option1</p>
              <p><b>Option2:</b> @optionsAccessor.Value.Option2</p>
              

              访问 MVC 视图文件中的配置

              以下代码显示 MVC 视图中的配置数据:

              @using Microsoft.Extensions.Configuration
              @inject IConfiguration Configuration
              Configuration value for 'MyKey': @Configuration["MyKey"]
              

              访问 Program.cs 中的配置

              以下代码访问 Program.cs 文件中的配置。

              var builder = WebApplication.CreateBuilder(args);
              var app = builder.Build();
              app.MapGet("/", () => "Hello World!");
              var key1 = app.Configuration.GetValue<int>("KeyOne");
              var key2 = app.Configuration.GetValue<bool>("KeyTwo");
              app.Logger.LogInformation($"KeyOne = {key1}");
              app.Logger.LogInformation($"KeyTwo = {key2}");
              app.Run();
              

              使用委托来配置选项

              在委托中配置的选项替代在配置提供程序中设置的值。

              在以下代码中,向服务容器添加了 IConfigureOptions<TOptions> 服务。 它使用委托来配置 MyOptions 的值:

              using SampleApp.Models;
              var builder = WebApplication.CreateBuilder(args);
              builder.Services.AddRazorPages();
              builder.Services.Configure<MyOptions>(myOptions =>
                  myOptions.Option1 = "Value configured in delegate";
                  myOptions.Option2 = 500;
              var app = builder.Build();
              

              以下代码显示选项值:

              public class Test2Model : PageModel
                  private readonly IOptions<MyOptions> _optionsDelegate;
                  public Test2Model(IOptions<MyOptions> optionsDelegate )
                      _optionsDelegate = optionsDelegate;
                  public ContentResult OnGet()
                      return Content($"Option1: {_optionsDelegate.Value.Option1} \n" +
                                     $"Option2: {_optionsDelegate.Value.Option2}");
              

              在前面的示例中,Option1Option2 的值在 appsettings.json 中指定,然后被配置的委托替代。

              主机与应用配置

              在配置并启动应用之前,配置并启动主机。 主机负责应用程序启动和生存期管理。 应用和主机均使用本主题中所述的配置提供程序进行配置。 应用的配置中也包含主机配置键值对。 有关在构建主机时如何使用配置提供程序,以及配置源如何影响主机配置的详细信息,请参阅 ASP.NET Core 基础知识概述

              默认主机配置

              有关使用 Web 主机时默认配置的详细信息,请参阅本主题的 ASP.NET Core 2.2 版本

            • 主机配置通过以下方式提供:
              • 使用环境变量配置提供程序通过前缀为 DOTNET_的环境变量(例如,DOTNET_ENVIRONMENT)提供。 在配置键值对加载后,前缀 (DOTNET_) 会遭去除。
              • 使用命令行配置提供程序通过命令行参数提供。
              • 已建立 Web 主机默认配置 (ConfigureWebHostDefaults):
                • Kestrel 用作 Web 服务器,并使用应用的配置提供程序对其进行配置。
                • 添加主机筛选中间件。
                • 如果 ASPNETCORE_FORWARDEDHEADERS_ENABLED 环境变量设置为 true,则添加转发的标头中间件。
                • 启用 IIS 集成。
                • 本主题仅与应用配置相关。 运行和托管 ASP.NET Core 应用的其他方面是使用本主题中未包含的配置文件进行配置:

                • launch.json/launchSettings.json 是用于开发环境的工具配置文件,如
  •