asp.net core 系列之Configuration
在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的顺序:
- Files (appsettings.json, appsettings.{Environment}.json, {Environment}是应用当前的运行环境)
- Azure Key Vault
- User secrets (Secret Manager)(仅用在开发环境)
- Environment variables
- 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的调用.
- 在项目目录打开命令行
- 把命令行参数用到 dotnet run 命令,dotnet run CommandLineKey=CommandLineValue
- 在应用运行之后,打开浏览器到应用的 http://localhost:5000
- 观察输出(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的调用.
- 运行示例应用。浏览 http://localhost:5000
- 观察环境变量的输出。
环境变量以下面的开头:
- 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文件中加载
- 运行示例应用。浏览 http://localhost:5000
- 观察配置中的输出
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的更多相关文章
- asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)
一.连接字符串 在上二篇中,ASP.NET Core 应用程序连接字符串是写死在ConfigureServices代码中,下面介绍通过配置来实现.连接字符串可以存储在 appsettings.json ...
- asp.net core 系列 17 通用主机 IHostBuilder
一.概述 ASP.NET Core 通用主机 (HostBuilder),该主机对于托管不处理 HTTP 请求的应用非常有用.通用主机的目标是将 HTTP 管道从 Web 主机 API 中分离出来,从 ...
- asp.net core 系列 16 Web主机 IWebHostBuilder
一.概述 在asp.net core中,Host主机负责应用程序启动和生存期管理.host主机包括Web 主机(IWebHostBuilder)和通用主机(IHostBuilder).Web 主机是适 ...
- ASP.NET Core系列(二):创建第一个.Net Core 项目
前面讲过 .NET Core简介及开发环境安装,本章会讲一讲ASP.NET Core 2.0的项目结构,查看完整的ASP.NET Core系列文章:https://www.cnblogs.com/zh ...
- ASP.NET Core系列(三):启动类Startup
前面讲了ASP.NET Core 的项目结构,查看完整的ASP.NET Core系列文章:https://www.cnblogs.com/zhangweizhong/category/1477144. ...
- Asp.net Core 系列之--5.认证、授权与自定义权限的实现
ChuanGoing 2019-11-24 asp.net core系列已经来到了第五篇,通过之前的基础介绍,我们了解了事件订阅/发布的eventbus整个流程,初探dapper ORM实现,并且简单 ...
- 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 ...
- 【目录】asp.net core系列篇
随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...
- asp.net core系列 76 Apollo 快速安装模式下填坑和ASP.NetCore结合使用
前言:由于公司占时没有运维,出于微服务的需要,Apollo只能先装在windows 阿里云上跑起来,由于环境及网络等问题,在安装过程中遇到很多坑,算是一个个坑填完后,最终实现. 一. java jdk ...
随机推荐
- easyui Full Layout
@{ Layout = null;}<!DOCTYPE html><html><head> <meta name="viewport&q ...
- 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
- WPF 鼠标在图片Image上悬停时切换更改设置图片源Source
// 无效的写法,图片不会被切换 <Image Margin="0,0,0,0" Width="50" Height="50" Sou ...
- 子函数内malloc分配内存,论如何改变指针参数所指内存,二级指针、三级指针的应用
工作中优化一段代码,代码中有一大段分配堆内存的内容,我觉得这段代码太长了,更适合放在子函数里面. 我把指针作为参数,然后在子函数中malloc分配内存,结果出现了问题,函数结束后,以参数传进来的指针并 ...
- Elasticsearch教程(二)java集成Elasticsearch
1.添加maven <!--tika抽取文件内容 --> <dependency> <groupId>org.apache.tika</groupId> ...
- 使用 Visual Studio 开发并调试 Mail Add-in (mail app for Outlook)
准备工作 如果你的邮箱搭建在 Exchange Server 上,则可以创建邮件应用程序(Mail Add-in)来扩展Office本身的功能,使用 Office Add-in Model 开发的 M ...
- DLL中类的显式链接(用虚函数进行显式链接)
DLL的显式链接在某些时候比隐式链接具有更大的灵活性.比如,如果在运行时发现DLL无法找到,程序可以显示一个错误信息并能继续运行.当你想为你的程序提供插件服务时,显式链接也很有用处. 显式链接到全局C ...
- Codility----OddOccurrencesInArray
Task description A non-empty zero-indexed array A consisting of N integers is given. The array conta ...
- 常用URL分享,实用地址
常用地址 文库文档免费下载地址1:http://www.hiwenku.com/ 文库文档免费下载下载2:http://www.20009.net/wk.html google地图拾取器:http:/ ...
- Android开发之旅(1) 之 Android 开发环境搭建
工作室原创出品,欢迎转载,欢迎交流. 转载请注明原文:http://www.cnblogs.com/wangleiblog/p/6019063.html Android开发之旅目录 1 前言 很多朋友 ...