在ASP.NET Core中的App configuration 是通过configuration providers基于key-value对建立的。Configuration providers读取配置文件到key-value,从多种配置源中:

  • Azure key Vault
  • Command-line arguments
  • Custom providers(installed or created)
  • Directory files
  • Environment variables
  • In-memory .NET objects
  • Setting files

用于提供Configuration配置的包是包含在Microsoft.AspNetCore.App metapackage里。下面的代码示例,将会使用Microsoft.Extensions.Configuration命名空间。

using Microsoft.Extensions.Configuration;

一.概述

1.Host vs App configuration(对比)

在应用配置和启动之前,host被配置和launched(发动,开展)。Host 负责应用的startup和生命周期管理。应用和主机都是用这个主题描述的configuration providers来配置。主机配置的key-values对成为应用全局配置的一部分。

2.Default configuration

ASP.NET Core基础上的Web应用 dotnet new templates(模板)会调用CreateDefaultBuilder,当建立host时,CreateDefaultBuilder为应用提供默认的配置,以下面的顺序:

(1).主机配置是被下面这些提供的:

  • 以ASPNETCORE_为前缀的环境变量(例如,ASPNETCORE_ENVIRONMENT)使用Environment Variables Configuration Provider. 当configuration key-values对被加载时,前缀(ASPNETCORE_)被去掉。
  • 命令行参数使用Command-line Configuration Provider提供

(2).应用配置是被下面这些提供的:

  • appsettings.json使用File Configuration Provider提供
  • appsetting.{Environment}.json使用File Configuration Provider提供
  • 当应用运行在Development environment(开发环境), Secret Manager使用entry程序集(entry:入口)
  • 环境变量使用Environment Variables Configuration Provider. 如果一个自定义前缀被使用了,这个前缀会在configuration key-value pairs被加载时去掉。(例如, PREFIX_ with .AddEnvironmentVariables(prefix:”PREFIX_”)).
  • Command-line 参数使用command-line Configuration Provider

3.Security

采用下面的最佳实践:

  • 不要存储密码或者其他敏感数据在configuration provider code或者 plain text configuration files.
  • 不要在开发和测试环境使用production secrets
  • 在项目外,指定secrets,以便它们不会被意外提交到源代码仓库

4.Hierarchical configuration data(分层的配置数据)

在下面的JSON文件中,结构化分层的两个sections中存在四个key:

{
"section0": {
"key0": "value",
"key1": "value"
},
"section1": {
"key0": "value",
"key1": "value"
}
}

当文件被读取到配置中时,唯一的key被创建,来维护原始配置源中的分层数据结构。

Section和key被使用冒号展开来维持原始结构:

section0:key0

section0:key1

section1:key0

section1:key1

如上,每个值都可以被唯一的取到。

GetSection和GetChildren方法可以被用来分离配置数据中的sections和section的children 。这些方法会在随后的GetSection,GetChildren,和Exists描述。GetSection是在Microsoft.Extensions.Configuration包中,这个包是在Microsoft.AspNetCore.App metapackage.

5.Conventions(习惯,约定)

这里是一些习惯的约定。

在应用启动时,配置源按照它们的configuration provider被指定的顺序来被读取。

Configuration providers实现了变化检测,Configuration providers可以重新加载配置,当一个基础的设置被改变时。例如,File Configuration Provider和Azure key Value Configuration Provider实现了变化检测。

IConfiguration在应用的依赖注入(DI)容器中是可用的。IConfiguration可以被注入到一个Razor Pages Pagemodel来包含一个配置的类。

public class IndexModel : PageModel
{
private readonly IConfiguration _config; public IndexModel(IConfiguration config)
{
_config = config;
} // The _config local variable is used to obtain configuration
// throughout the class.
}

Configuration providers不能使用DI,因为当它们(Configuration providers)被host建立时,DI是不可用的。

Configuration keys采用下面的约定:

  • Keys忽略大小写。例如ConnectionString和connectionstring被认为是相同的键(keys)
  • If a value for the same key is set by the same or different configuration providers, the last value set on the key is the value used.(如果同一个key的值被不同的数据提供器设置,会默认使用后面设置的,按configuration providers指定的顺序)
  • 分层keys
    • 在Configuration API中,冒号:可以在所有平台起作用
    • 在环境变量中,冒号可能不能在所有平台起作用。双下划线(__)被所有平台支持并且转化为冒号
    • 在Azure Key Vault,分层的keys用--(两个中杠)作为分割符,你必须提供代码来用冒号替换这两个中杠。当secrets被加载到应用的配置中时。
  • ConfigurationBinder支持绑定数组到对象,在配置keys中使用array 标识体。数组绑定会在Bind an array to class节描述。

Configuratian values采用下面的约定:

  • Values都是string
  • Null值不能被存储在配置中或者绑定到对象

6.Providers

下面列出了ASP.NET Core应用可用的configuration providers:

Configuration sources(配置源)按照它们的configuration providers在startup中指定的顺序被顺序读取。

典型的configuration providers的顺序:

  1. Files (appsettings.json, appsettings.{Environment}.json, {Environment}是应用当前的运行环境)
  2. Azure Key Vault
  3. User secrets (Secret Manager)(仅用在开发环境)
  4. Environment variables
  5. Command-line arguments

这是一种通用的实践,把命令行配置源放到最后,使它可以重写其他配置源设置的配置。

注意:后面的配置会覆盖前面的配置

7.ConfigureAppConfiguration

调用ConfigureAppConfiguration,当需要建立host来指定除了被CreateDefaultBuilder自动添加配置源外的其他配置源:

public class Program
{
public static Dictionary<string, string> arrayDict =
new Dictionary<string, string>
{
{"array:entries:0", "value0"},
{"array:entries:1", "value1"},
{"array:entries:2", "value2"},
{"array:entries:4", "value4"},
{"array:entries:5", "value5"}
}; public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddInMemoryCollection(arrayDict);
config.AddJsonFile(
"json_array.json", optional: false, reloadOnChange: false);
config.AddJsonFile(
"starship.json", optional: false, reloadOnChange: false);
config.AddXmlFile(
"tvshow.xml", optional: false, reloadOnChange: false);
config.AddEFConfiguration(
options => options.UseInMemoryDatabase("InMemoryDb"));
config.AddCommandLine(args);
})
.UseStartup<Startup>();
}

二.configuration provider讲解

8.Command-line Configuration Provider

在运行时,CommandLineConfigurationProviders从command line argument key-value pairs中加载配置.

要想启动command-line 配置,AddCommandLine扩展方法需要在ConfigurationBuilder实例中被调用。

AddCommandLine早已被CreateDefaultBuilder调用。如果你需要提供 app configuration 并且仍然可以用command-line arguments重写配置,在ConfigureAppConfiguration中,调用app的额外的providers,并且在最后调用AddCommandLine.

public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
// Call other providers here and call AddCommandLine last.
config.AddCommandLine(args);
})
.UseStartup<Startup>();
}

当直接创建一个WebHostBuilder时,调用UseConfiguration(另一种用法):

var config = new ConfigurationBuilder()
// Call additional providers here as needed.
// Call AddCommandLine last to allow arguments to override other configuration.
.AddCommandLine(args)
.Build(); var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();

Example

示例应用功能利用静态方法CreateDefaultBuilder来建立host,它包含对AddCommandLine的调用.

  1. 在项目目录打开命令行
  2. 把命令行参数用到 dotnet run 命令,dotnet run CommandLineKey=CommandLineValue
  3. 在应用运行之后,打开浏览器到应用的 http://localhost:5000
  4. 观察输出(dotnet run)。

Arguments

值必须是下面的形式.=后面的值可以为null(例如,CommandLineKey=)

在同一个命令窗口中,不要混合使用=号和空格

dotnet run CommandLineKey1=value1 --CommandLineKey2=value2 /CommandLineKey3=value3
dotnet run --CommandLineKey1 value1 /CommandLineKey2 value2
dotnet run CommandLineKey1= CommandLineKey2=value2

Switch mappings

Switch mapping dictionary key rules:

  • Swithes必须以-或者- - 开头
  • Swith mappings不能包含重复的keys

当建立host指定应用配置时,调用ConfigureAppConfiguration:

public class Program
{
public static readonly Dictionary<string, string> _switchMappings =
new Dictionary<string, string>
{
{ "-CLKey1", "CommandLineKey1" },//把命令行中key为-CLKey1的键替换为key为CommandLineKey1
{ "-CLKey2", "CommandLineKey2" }
}; public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} // Do not pass the args to CreateDefaultBuilder
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddCommandLine(args, _switchMappings);
})
.UseStartup<Startup>();
}

当switch mappings dictionary被创建后,包含下面的数据:

如果启动应用时,switch-mapped keys被使用,configuration会在dictionary提供的key里接收到配置值。

dotnet run -CLKey1=value1 -CLKey2=value2

在运行之前的命令后,configuration包含了值,如下表:

如上,可以看出Switch mappings的作用是:

把命令行中输入的key替换为switch mapping中的key值。

9.Environment Variables Configuration Provider

要启用environment variables configuration,需要调用AddEnvironmentVariables扩展方法。

AddEnvironmentVariables用来加载以ASPNETCORE_开头的环境变量。

当建立host指定应用配置时,调用ConfigureAppConfiguration :

public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
// Call additional providers here as needed.
// Call AddEnvironmentVariables last if you need to allow
// environment variables to override values from other
// providers.
config.AddEnvironmentVariables(prefix: "PREFIX_");
})
.UseStartup<Startup>();
}

当直接创建WebHostBuilder,调用UseConfiguration:

var config = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build(); var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();

Example

示例应用功能利用静态方法CreateDefaultBuilder来建立host,它包含对AddEnvironmentVariables的调用.

  1. 运行示例应用。浏览 http://localhost:5000
  2. 观察环境变量的输出。

环境变量以下面的开头:

  • ASPNETCORE_
  • urls
  • Logging
  • ENVIRONMENT
  • contentRoot
  • AllowedHosts
  • applicationName
  • CommandLine

如果你希望在应用中暴露这些环境变量可用,在Pages/Index.cshtml.cs中改变FilteredConfiguration为下面:

FilteredConfiguration = _config.AsEnumerable();

Prefixes

当你应用一个前缀到AddEnvironmentVariables方法,应用配置中的环境变量可以被过滤。例如,在前缀CUSTOM_上过滤环境变量,应用前缀到configuration provider:

var config = new ConfigurationBuilder()
.AddEnvironmentVariables("CUSTOM_")
.Build();

前缀会被分离,当配置key-values pairs被创建时。

静态方法CreateDefaultBuilder会创建一个WebHostBuilder来建立应用主机。当WebHostBuilder被创建时,可以在环境变量中找到ASPNETCORE_为前缀的主机配置。

(1).Connection string prefixes

Configuration API(配置api)对于四个连接字符串环境变量有特殊的处理规则。如果没有前缀作用到AddEnvironmentVariables,带有下面前缀的环境变量会被加载到应用中

当一个环境变量被发现,并且带有上面四个之一的前缀被加载到配置:

  • configuration key通过移除环境变量前缀来创建,并且增加一个configuration key section(ConnectionStrings)
  • 一个新的configuration key-value pair被创建了,它代表database connection provider。(只有CUSTOMCONNSTR_,which has no stated provider).

10.File Configuration Provider

FileConfigurationProvider是从文件系统中加载配置的基础类。下面的configuration providers是作用特定的文件类型:

  • INI Configuration Provider
  • JSON Configuration Provider
  • XML Configuration Provider

INI Configuration Provider

IniConfigurationProvider从INI文件中加载配置。

要启用INI 文件配置,在ConfigurationBuilder实例中调用AddIniFile扩展方法。

重写一些指定配置选项:

  • 文件是否是可选的
  • 如果文件改变,配置是否重新加载
  • IFileProvider用于获取文件

调用ConfigureAppConfiguration,当建立host指定应用配置时:

public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddIniFile(
"config.ini", optional: true, reloadOnChange: true);
})
.UseStartup<Startup>();
}

基础路径(base path)是通过SetBasePath设置。SetBasePath是在Microsoft.Extensions.Configuration.FileExtension包中,这个包是在Microsoft.AspNetCore.App metapackage.

当直接创建一个WebHostBuilder,调用UseConfiguration:

var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddIniFile("config.ini", optional: true, reloadOnChange: true)
.Build(); var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();

一个INI configuration file示例:

[section0]
key0=value
key1=value [section1]
subsection:key=value [section2:subsection0]
key=value [section2:subsection1]
key=value

上面的配置文件加载下面的key和value:

  • section0:key0
  • section0:key1
  • section1:subsection:key
  • section2:subsection0:key
  • section2:subsection1:key

JSON Configuration Provider

JsonConfigurationProvider从JSON文件中加载配置.

要启用JSON文件配置,在ConfigurationBuilder实例上,调用AddJsonFile扩展方法。

重写一些指定配置选项:

  • 文件是否是可选的
  • 如果文件改变,配置是否重新加载
  • IFileProvider用于获取文件

AddJsonFile会自动调用两次,当你用CreateDefaultBuilder初始化一个WebHostBuilder时。这个方法被调用加载配置,从下面的:

  • appsettings.json - 这个文件被首先读取。这个文件的环境版本可以重写appsettings.json文件提供的值。
  • appsettings.{Environment}.json - 这个文件的环境版本(environment version)依据于IHostingEnvironment.EnvironmentName被加载

调用ConfiureAppConfiguration,当建立host来指定应用配置,通过其他文件而不是通过appsettings.json和appsettings.{Environment}.json文件。

public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddJsonFile(
"config.json", optional: true, reloadOnChange: true);
})
.UseStartup<Startup>();
}

当直接创建WebHostBuilder,调用UseConfiguration:

var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("config.json", optional: true, reloadOnChange: true)
.Build(); var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();

Example

示例应用利用静态方法CreateDefaultBuilder来建立host,它包含两次对AddJsonFile的调用。配置从appsettings.json和appsettings.{Environment}.json文件中加载

  1. 运行示例应用。浏览 http://localhost:5000
  2. 观察配置中的输出

XML Configuration Provider

XmlConfigurationProvider从XML文件中加载配置。

要启用XML文件配置,在ConfigurationBuilder实例上调用AddXmlFile扩展方法。

配置文件的根节点被忽略了,当配置key-value pairs被创建了。不要在文件中指定一个Document Type Definition(DTD)或者命名空间。

调用ConfigureAppConfiguration,当建立host来指定应用的配置时:

public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddXmlFile(
"config.xml", optional: true, reloadOnChange: true);
})
.UseStartup<Startup>();
}

当直接创建WebHostBuilder,调用UseConfiguration:

var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddXmlFile("config.xml", optional: true, reloadOnChange: true)
.Build(); var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();

(1).XML配置文件可以使用distinct元素名称对于repeating sections:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<section0>
<key0>value</key0>
<key1>value</key1>
</section0>
<section1>
<key0>value</key0>
<key1>value</key1>
</section1>
</configuration>

前面的配置文件在家下面的key和value:

  • section0:key0
  • section0:key1
  • section1:key0
  • section1:key1

(2).还可以如下,用name属性区分元素的形式:

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

之前的配合文件加载下面的key和value:

  • section:section0:key:key0
  • section:section0:key:key1
  • section:section1:key:key0
  • section:section1:key:key1

(3).属性也可以用于值上:

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

之前的配置文件加载下面的key和value:

  • key:attribute
  • section:key:attribute

11.Key-per-file Configuration Provider

KeyPerFileConfigurationProvider使用一个目录文件作为configuration key-value pairs.其中key是文件名。 value包含文件内容。Key-per-file Configuration Provider用于Docker hosting 场景。

要启用key-per-file configuration, 在ConfigurationBuilder实例上,调用AddKeyPerFile扩展方法。文件的目录路径(directoryPath)必须是绝对路径。

Overloads permit specifying:

  • Action<KeyPerFileConfigurationSource>委托 ,来配置source
  • 目录是否是可选的,和目录路径

在文件名字中,双下划线(__)用作一个configuration key 分隔符。例如,文件名Logging__LogLevel__System产生configuration key : Logging:logLevel:System

调用ConfigureAppConfiguration,当建立host来指定应用的配置时:

public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
var path = Path.Combine(
Directory.GetCurrentDirectory(), "path/to/files");
config.AddKeyPerFile(directoryPath: path, optional: true);
})
.UseStartup<Startup>();
}

当直接创建WebHostBuilder时,调用UseConfiguration:

var path = Path.Combine(Directory.GetCurrentDirectory(), "path/to/files");
var config = new ConfigurationBuilder()
.AddKeyPerFile(directoryPath: path, optional: true)
.Build(); var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();

12.Memory Configuration Provider

MemoryConfigurationProvider使用内存集合作为配置key-value pairs.

要使用in-memory collection configuration,在ConfigurationBuilder实例上,调用AddInMemoryCollection扩展方法。

The configuration provider可以使用IEnumerable<KeyValuePair<String,String>>来初始化。

当建立host来指定应用配置时,调用ConfigureAppConfiguration:

public class Program
{
public static readonly Dictionary<string, string> _dict =
new Dictionary<string, string>
{
{"MemoryCollectionKey1", "value1"},
{"MemoryCollectionKey2", "value2"}
}; public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddInMemoryCollection(_dict);
})
.UseStartup<Startup>();
}

当直接创建WebHostBuilder时,调用UseConfiguration:

var dict = new Dictionary<string, string>
{
{"MemoryCollectionKey1", "value1"},
{"MemoryCollectionKey2", "value2"}
}; var config = new ConfigurationBuilder()
.AddInMemoryCollection(dict)
.Build(); var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();

三.其他

13.GetValue

ConfigurationBinder.GetValue<T> 从配置文件中用特定的key提出value,并且转化为特定类型。如果这个key没找到,可以提供默认值。

下面的例子:

  • 用key为NumberKey,从配置中提取string value.如果NumberKey没有在配置中找到,默认的value值99会被使用
  • 把这个value转化为int类型
  • 通过page存储值
public class IndexModel : PageModel
{
public IndexModel(IConfiguration config)
{
_config = config;
} public int NumberConfig { get; private set; } public void OnGet()
{
NumberConfig = _config.GetValue<int>("NumberKey", );
}
}

14.GetSection, GetChildren, and Exists

{
"section0": {
"key0": "value",
"key1": "value"
},
"section1": {
"key0": "value",
"key1": "value"
},
"section2": {
"subsection0" : {
"key0": "value",
"key1": "value"
},
"subsection1" : {
"key0": "value",
"key1": "value"
}
}
}

当文件被读取到配置中,如下:

  • section0:key0
  • section0:key1
  • section1:key0
  • section1:key1
  • section2:subsection0:key0
  • section2:subsection0:key1
  • section2:subsection1:key0
  • section2:subsection1:key1

GetSection

IConfiguration.GetSection用特定的subsection key提取一个configuration subsection.

要返回一个包含在section1中的key-value pairs的IConfigurationSection,调用GetSection并且应用section name:

var configSection = _config.GetSection("section1");

其中configSection没有value,只有一个key和path.

相似的,要包含key为section2:subsection0的value,调用GetSection并且应用section path:

var configSection = _config.GetSection("section2:subsection0");

GetSection不会返回null。 如果没有匹配的section,一个空的IConfigurationSection会被返回。

GetChildren

调用在section2上的IConfiguration.GetChildren包含:

  • subsection0
  • subsection1
var configSection = _config.GetSection("section2");
var children = configSection.GetChildren();

Exists

用ConfigurationExtensions.Exists来确定configuration section是否存在:

var sectionExists = _config.GetSection("section2:subsection2").Exists();

给出的例子中的数据,sectionExists是false,因为section2:subsection2这个section不存在。

15.Bind to a class

配置可以被绑定到类中。

示例包含一个Startship的model(Models/Starship.cs):

public class Starship
{
public string Name { get; set; }
public string Registry { get; set; }
public string Class { get; set; }
public decimal Length { get; set; }
public bool Commissioned { get; set; }
}

Starship.json文件中starship的section节创建了配置,当示例应用使用JSON Configuration Provider加载配置时。

{
"starship": {
"name": "USS Enterprise",
"registry": "NCC-1701",
"class": "Constitution",
"length": 304.8,
"commissioned": false
},
"trademark": "Paramount Pictures Corp. http://www.paramount.com"
}

下面的配置被创建了:

示例应用利用key为starship来调用GetSection。Starship key-value pairs被分离。在绑定实例值后:

var starship = new Starship();
_config.GetSection("starship").Bind(starship);
Starship = starship;

16.Bind to an object graph

示例绑定一个TvShow的model,它包含Metadata和Actors类:

public class TvShow
{
public Metadata Metadata { get; set; }
public Actors Actors { get; set; }
public string Legal { get; set; }
} public class Metadata
{
public string Series { get; set; }
public string Title { get; set; }
public DateTime AirDate { get; set; }
public int Episodes { get; set; }
} public class Actors
{
public string Names { get; set; }
}

示例应用有个tvshow.xml文件包含配置数据:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<tvshow>
<metadata>
<series>Dr. Who</series>
<title>The Sun Makers</title>
<airdate>//</airdate>
<episodes></episodes>
</metadata>
<actors>
<names>Tom Baker, Louise Jameson, John Leeson</names>
</actors>
<legal>(c) BBC https://www.bbc.co.uk/programmes/b006q2x0</legal>
</tvshow>
</configuration>

配置被Bind方法绑定到了TvShow对象上。如下:

var tvShow = new TvShow();
_config.GetSection("tvshow").Bind(tvShow);
TvShow = tvShow;

ConfigurationBinder.Get<T>绑定和返回指定的类型。Get<T>比使用Bind更方便。下面的代码展示了怎么再之前的代码使用Get<T>,如下:

TvShow = _config.GetSection("tvshow").Get<TvShow>();

17.Bind an array to a c lass

Bind还支持绑定数组.

In-memory array processing

考虑下面配置中的keys和values:

示例应用中的keys和values被使用Memory Configuration Provider被加载:

public class Program
{
public static Dictionary<string, string> arrayDict =
new Dictionary<string, string>
{
{"array:entries:0", "value0"},
{"array:entries:1", "value1"},
{"array:entries:2", "value2"},
{"array:entries:4", "value4"},
{"array:entries:5", "value5"}
}; public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddInMemoryCollection(arrayDict);
config.AddJsonFile(
"json_array.json", optional: false, reloadOnChange: false);
config.AddJsonFile(
"starship.json", optional: false, reloadOnChange: false);
config.AddXmlFile(
"tvshow.xml", optional: false, reloadOnChange: false);
config.AddEFConfiguration(
options => options.UseInMemoryDatabase("InMemoryDb"));
config.AddCommandLine(args);
})
.UseStartup<Startup>();
}

数组跳过了索引为3的值。Configuration binder不能绑定null 值或者创建null entries在绑定对象中。

在示例中,一个类用来绑定配置数据:

public class ArrayExample
{
public string[] Entries { get; set; }
}

配置数据被绑定到对象上:

var arrayExample = new ArrayExample();
_config.GetSection("array").Bind(arrayExample);

也可以使用ConfigurationBinder.Get<T>:

ArrayExample = _config.GetSection("array").Get<ArrayExample>();

ArrayExample的实例,接收到配置中的数组数据:

在绑定对象中,索引为3有的是array:4的值。

要处理这样的情况,可以这样,使用一个额外的JOSN Configuration Provider处理丢失的key-value pair, ArrayExample.Entries匹配完整的配置数组:

missing_value.json:

{
"array:entries:3": "value3"
}

在ConfigureAppConfiguration中:

config.AddJsonFile("missing_value.json", optional: false, reloadOnChange:false);

下面的值会被加载到配置中:

如果ArrayExample类的实例是在JSON Configuration Provider包含索引3后被绑定,ArrayExample.Entries数组会包含这个值:

JSON array processing

如果JSON文件包含一个数组,配置keys被创建为数组的索引。下面的配置文件中,subsection是一个数组:

{
"json_array": {
"key": "valueA",
"subsection": [
"valueB",
"valueC",
"valueD"
]
}
}

JSON Configuration Provider读取配置数据到下面所列:

在示例应用中,下面的类用来绑定配置数据:

public class JsonArrayExample
{
public string Key { get; set; }
public string[] Subsection { get; set; }
}

在绑定后,JsonArrayExample.Key有值valueA,subsection的值存储在Subsection属性的数组中。

四.对于自定义configuration provider

18.Custom configuration provider

示例应用说明怎么创建一个基础的configuration provider,它可以使用Entity Framework从数据库读取数据。

provider有下面特征:

  • EF in-memory database是用于证明目的。
  • 在startup中,provider读取数据库表到配置中.
  • Reload-on-change没有实现,所以在应用启动后更新数据库对于应用的配置没有作用。

定义个EFConfigurationValue实体来存储数据库中的配置数据。

Models/EFConfigurationValues.cs:

public class EFConfigurationValue
{
public string Id { get; set; }
public string Value { get; set; }
}

增加一个EFConfigurationContext来存储和取得配置值。

EFConfigurationProvider/EFConfigurationContext.cs:

public class EFConfigurationContext : DbContext
{
public EFConfigurationContext(DbContextOptions options) : base(options)
{
} public DbSet<EFConfigurationValue> Values { get; set; }
}

创建一个类实现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)
{
return new EFConfigurationProvider(_optionsAction);
}
}

创建一个自定义的configuration provider通过继承ConfigurationProvider.这个configuration provider初始化数据库,当它是空的时。

EFConfigurationProvider/EFConfigurationProvider.cs:

public class EFConfigurationProvider : ConfigurationProvider
{
public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
{
OptionsAction = optionsAction;
} Action<DbContextOptionsBuilder> OptionsAction { get; } // Load config data from EF DB.
public override void Load()
{
var builder = new DbContextOptionsBuilder<EFConfigurationContext>(); OptionsAction(builder); using (var dbContext = new EFConfigurationContext(builder.Options))
{
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
var configValues = new Dictionary<string, string>
{
{ "quote1", "I aim to misbehave." },
{ "quote2", "I swallowed a bug." },
{ "quote3", "You can't stop the signal, Mal." }
}; dbContext.Values.AddRange(configValues
.Select(kvp => new EFConfigurationValue
{
Id = kvp.Key,
Value = kvp.Value
})
.ToArray()); dbContext.SaveChanges(); return configValues;
}
}

一个AddEFConfiguration扩展方法允许增加配置源到一个ConfigurationBuilder.

Extensions/EntityFrameworkExtension.cs:

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

下面的代码展示了怎么在Program.cs中使用自定义的EFConfigurationProvider:

public class Program
{
public static Dictionary<string, string> arrayDict =
new Dictionary<string, string>
{
{"array:entries:0", "value0"},
{"array:entries:1", "value1"},
{"array:entries:2", "value2"},
{"array:entries:4", "value4"},
{"array:entries:5", "value5"}
}; public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddInMemoryCollection(arrayDict);
config.AddJsonFile(
"json_array.json", optional: false, reloadOnChange: false);
config.AddJsonFile(
"starship.json", optional: false, reloadOnChange: false);
config.AddXmlFile(
"tvshow.xml", optional: false, reloadOnChange: false);
config.AddEFConfiguration(
options => options.UseInMemoryDatabase("InMemoryDb"));
config.AddCommandLine(args);
})
.UseStartup<Startup>();
}

19.Access configuration during startup

在Startup.ConfigureServices中注入IConfiguration到Startup构造函数中来取得配置数据。要再Startup.Configure中取得配置数据,要么直接注入IConfiguration到方法中,要么使用构造函数中的实例:

public class Startup
{
private readonly IConfiguration _config; public Startup(IConfiguration config)
{
_config = config;
} public void ConfigureServices(IServiceCollection services)
{
var value = _config["key"];
} public void Configure(IApplicationBuilder app, IConfiguration config)
{
var value = config["key"];
}
}

20.Access configuration in a Razor Pages page or MVC view

在Razor Pages page或者MVC view中取得configuration settings.增加一个using指令为Microsoft.Extensions.Configuration 命名空间,并且把IConfiguration注入到page或者view中。

在Razor Pages page:

@page
@model IndexModel
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration <!DOCTYPE html>
<html lang="en">
<head>
<title>Index Page</title>
</head>
<body>
<h1>Access configuration in a Razor Pages page</h1>
<p>Configuration value for 'key': @Configuration["key"]</p>
</body>
</html>

在MVC view中:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration <!DOCTYPE html>
<html lang="en">
<head>
<title>Index View</title>
</head>
<body>
<h1>Access configuration in an MVC view</h1>
<p>Configuration value for 'key': @Configuration["key"]</p>
</body>
</html>

参考网址:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.2

asp.net core 系列之Configuration的更多相关文章

  1. asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)

    一.连接字符串 在上二篇中,ASP.NET Core 应用程序连接字符串是写死在ConfigureServices代码中,下面介绍通过配置来实现.连接字符串可以存储在 appsettings.json ...

  2. asp.net core 系列 17 通用主机 IHostBuilder

    一.概述 ASP.NET Core 通用主机 (HostBuilder),该主机对于托管不处理 HTTP 请求的应用非常有用.通用主机的目标是将 HTTP 管道从 Web 主机 API 中分离出来,从 ...

  3. asp.net core 系列 16 Web主机 IWebHostBuilder

    一.概述 在asp.net core中,Host主机负责应用程序启动和生存期管理.host主机包括Web 主机(IWebHostBuilder)和通用主机(IHostBuilder).Web 主机是适 ...

  4. ASP.NET Core系列(二):创建第一个.Net Core 项目

    前面讲过 .NET Core简介及开发环境安装,本章会讲一讲ASP.NET Core 2.0的项目结构,查看完整的ASP.NET Core系列文章:https://www.cnblogs.com/zh ...

  5. ASP.NET Core系列(三):启动类Startup

    前面讲了ASP.NET Core 的项目结构,查看完整的ASP.NET Core系列文章:https://www.cnblogs.com/zhangweizhong/category/1477144. ...

  6. Asp.net Core 系列之--5.认证、授权与自定义权限的实现

    ChuanGoing 2019-11-24 asp.net core系列已经来到了第五篇,通过之前的基础介绍,我们了解了事件订阅/发布的eventbus整个流程,初探dapper ORM实现,并且简单 ...

  7. Ajax跨域问题及解决方案 asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS) c#中的Cache缓存技术 C#中的Cookie C#串口扫描枪的简单实现 c#Socket服务器与客户端的开发(2)

    Ajax跨域问题及解决方案   目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP ...

  8. 【目录】asp.net core系列篇

    随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...

  9. asp.net core系列 76 Apollo 快速安装模式下填坑和ASP.NetCore结合使用

    前言:由于公司占时没有运维,出于微服务的需要,Apollo只能先装在windows 阿里云上跑起来,由于环境及网络等问题,在安装过程中遇到很多坑,算是一个个坑填完后,最终实现. 一. java jdk ...

随机推荐

  1. easyui Full Layout

    @{    Layout = null;}<!DOCTYPE html><html><head>    <meta name="viewport&q ...

  2. QList, QLinkedList, QVector, QStack, QQueue的区别,以前也没见过QCache,而且可以自定义cost

    http://doc.qt.io/qt-4.8/containers.html http://doc.qt.io/qt-4.8/qcache.html

  3. WPF 鼠标在图片Image上悬停时切换更改设置图片源Source

    // 无效的写法,图片不会被切换 <Image Margin="0,0,0,0" Width="50" Height="50" Sou ...

  4. 子函数内malloc分配内存,论如何改变指针参数所指内存,二级指针、三级指针的应用

    工作中优化一段代码,代码中有一大段分配堆内存的内容,我觉得这段代码太长了,更适合放在子函数里面. 我把指针作为参数,然后在子函数中malloc分配内存,结果出现了问题,函数结束后,以参数传进来的指针并 ...

  5. Elasticsearch教程(二)java集成Elasticsearch

    1.添加maven <!--tika抽取文件内容 --> <dependency> <groupId>org.apache.tika</groupId> ...

  6. 使用 Visual Studio 开发并调试 Mail Add-in (mail app for Outlook)

    准备工作 如果你的邮箱搭建在 Exchange Server 上,则可以创建邮件应用程序(Mail Add-in)来扩展Office本身的功能,使用 Office Add-in Model 开发的 M ...

  7. DLL中类的显式链接(用虚函数进行显式链接)

    DLL的显式链接在某些时候比隐式链接具有更大的灵活性.比如,如果在运行时发现DLL无法找到,程序可以显示一个错误信息并能继续运行.当你想为你的程序提供插件服务时,显式链接也很有用处. 显式链接到全局C ...

  8. Codility----OddOccurrencesInArray

    Task description A non-empty zero-indexed array A consisting of N integers is given. The array conta ...

  9. 常用URL分享,实用地址

    常用地址 文库文档免费下载地址1:http://www.hiwenku.com/ 文库文档免费下载下载2:http://www.20009.net/wk.html google地图拾取器:http:/ ...

  10. Android开发之旅(1) 之 Android 开发环境搭建

    工作室原创出品,欢迎转载,欢迎交流. 转载请注明原文:http://www.cnblogs.com/wangleiblog/p/6019063.html Android开发之旅目录 1 前言 很多朋友 ...