ASP.NET Core 中文文档 第三章 原理(7)配置
原文:Configuration
作者:Steve Smith、Daniel Roth
翻译:刘怡(AlexLEWIS)
校对:孟帅洋(书缘)
ASP.NET Core 支持多种配置选项。应用程序配置数据内建支持读取 JSON、XML 和 INI 格式的配置文件和环境变量。你也可以编写自己的自定义配置提供程序。
章节:
获取和设置配置
ASP.NET Core 配置系统针对以前的 ASP.NET 版本(依赖于 System.Configuration
和 XML 配置文件(如 Web.config
))进行了重新架构。新的配置模型提供了精简高效的通过检索多样化提供程序的获取基于键/值对配置的能力。应用程序和框架可以通过新的选择模式访问配置。
在 ASP.NET 应用程序中,建议你在应用程序的 Startup
类中只实例化一个 Configuration
实例。然后使用选择模式来访问各自的设置。
简单来说,Configuration
类只是一个提供了读写名/值对能力的 Providers
集合。你至少需要配置一个提供程序,使得 Configuration
能正常工作。下例演示了如何测试把 Configuration
作为一个键/值对存储来处理。
var builder = new ConfigurationBuilder();
builder.AddInMemoryCollection();
var config = builder.Build();
config["somekey"] = "somevalue";
// do some other work
var setting = config["somekey"]; // also returns "somevalue"
注意
你必须至少设置一个配置提供程序。
一般不会把配置值存储在一个有层次的结构中,尤其是使用外部文件(如 JSON、XML、INI)时。在此情况下,可以使用以 :
符号分隔(从层次结构的根开始)的键来取回配置值。以下面的 appsettings.json 文件为例:
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-WebApplication1-26e8893e-d7c0-4fc6-8aab-29b59971d622;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
应用程序使用 configuration 配置正确的连接字符串。可以通过键 Data:DefaultConnection:ConnectionString
来访问 ConnectionString
的设置。
应用程序所需要的设置和指定配置的机制(configuration 便是一例)都可通过使用选择模式解耦。创建自己的配置类(可以是几个不同的类,分别对应不同的配置组),而后通过选项服务注入到应用程序中。然后你就可以通过配置或其它你所选择的机制来设置了。
注意
你可将Configuration
实例设计为一个服务,但这会导致不必要地把应用程序和配置系统与指定配置键耦合在一起。相反可通过选择模式来避免这一问题。
使用内建提供程序
配置框架已内建支持 JSON、XML 和 INI 配置文件,内存配置(直接通过代码设置值),从环境变量和命令行参数中拉取配置。开发者并不受限于必须使用单个配置提供程序。事实上可以把多个配置提供程序组合在一起,就像是用从当前存在的另一个配置提供程序中获取配置值覆盖默认配置一样。
扩展方法支持为配置添加额外的配置文件提供程序。这些方法能被独立的或链式的(如 fluent API)调用在 ConfigurationBuilder
实例之上,如下所示:
// work with with a builder using multiple calls
var builder = new ConfigurationBuilder();
builder.SetBasePath(Directory.GetCurrentDirectory());
builder.AddJsonFile("appsettings.json");
var connectionStringConfig = builder.Build();
// chain calls together as a fluent API
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.AddEntityFrameworkConfig(options =>
options.UseSqlServer(connectionStringConfig.GetConnectionString("DefaultConnection"))
)
.Build();
指定配置提供程序的顺序非常重要,这将影响它们的设置被应用的优先级(如果存在于多个位置)。上例中,如果相同的配置同时存在于 appsettings.json 和环境变量,则环境变量的设置将被最终使用。最后指定的配置提供程序将“获胜”(如果该设置存在于至少两处位置)。ASP.NET 团队建议最后指定环境变量,如此一来本地环境可以覆盖任何部署在配置文件中的设置。
注意
如果通过环境变量重写嵌套键,请把变量中键名的:
替换为__
(两个下划线)。
这对于指定环境的配置文件非常有用,这能通过以下代码来实现:
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); //手动高亮
if (env.IsDevelopment())
{
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
IHostingEnvironment
服务用于获取当前环境。在 Development
环境中,上例高亮行代码将寻找名为 appsettings.Development.json
的配置文件,并用其中的值覆盖当前存在的其它值。更多请参见 environments。
警告
谨记,严禁把密码或其他敏感数据保存在代码或纯文本配置文件中,严谨在开发环境或测试环境中使用生产环境的机密数据(这些机密数据应当在项目树的外部被指定,这样就不会意外提交到仓库内)。移步了解更多 environments 和管理 Safe storage of app secrets during development。
影响 Configuration
优先级顺序的一个因素是指定可被重写的默认值。在本控制台应用程序中,默认的 username
设置由 MemoryConfigurationProvider
指定,但如果命令行参数中有个 username
参数被传递给应用程序,它将被覆盖。在输出中可以看到程序的每一个步骤中有多少个配置提供程序在进行配置工作。
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
namespace ConfigConsole
{
public static class Program
{
public static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
Console.WriteLine("Initial Config Sources: " + builder.Sources.Count());
builder.AddInMemoryCollection(new Dictionary<string, string>
{
{ "username", "Guest" }
});
Console.WriteLine("Added Memory Source. Sources: " + builder.Sources.Count());
builder.AddCommandLine(args); //手动高亮
Console.WriteLine("Added Command Line Source. Sources: " + builder.Sources.Count());
var config = builder.Build(); //手动高亮
string username = config["username"];
Console.WriteLine($"Hello, {username}!");
}
}
}
当运行时,程序将显示默认值,除非使用命令行参数重写之。
使用选项和配置对象
通过使用选择模式(options pattern)你可将任何类或 POCO(Plain Old CLR Object)转换为设置类。推荐把你创建的配置根据应用程序的功能分解为多个配置对象,从而实现 ISP(Interface Segregation Principle,接口隔离原则,类只依赖于它们自己使用的配置设置)和 SoC(Separation of Concerns,关注分离,设置与应用程序相互隔离,减少彼此之间的干扰和影响)。
一个简单的 MyOptions
类如下所示:
public class MyOptions
{
public string Option1 { get; set; }
public int Option2 { get; set; }
}
通过 IOptions<TOptions>
,配置选项将被注入到应用程序中。比方说,如 controller 使用 IOptions<TOptions>
来访问需要在 Index
视图中渲染的配置:
public class HomeController : Controller
{
private readonly IOptions<MyOptions> _optionsAccessor; //手动高亮
public HomeController(IOptions<MyOptions> optionsAccessor) //手动高亮
{
_optionsAccessor = optionsAccessor;
} //手动高亮
// GET: /<controller>/
public IActionResult Index() => View(_optionsAccessor.Value);
}
建议
更多请浏览 Dependency Injection。
为设置 IOptions<TOption>
服务,你需在启动期间在 ConfigureServices
方法内调用 AddOptions()
扩展方法。
public void ConfigureServices(IServiceCollection services)
{
// Setup options with DI
services.AddOptions();//手动高亮
Index
视图将显示配置选项:
配置选项使用 Configure<TOption>
扩展方法。你可以通过委托或绑定配置选项的方式来进行配置:
public void ConfigureServices(IServiceCollection services)
{
// Setup options with DI
services.AddOptions(); //手动高亮
// Configure MyOptions using config by installing Microsoft.Extensions.Options.ConfigurationExtensions
services.Configure<MyOptions>(Configuration);
// Configure MyOptions using code
services.Configure<MyOptions>(myOptions => //手动高亮
{
myOptions.Option1 = "value1_from_action"; //手动高亮
}); //手动高亮
// Configure MySubOptions using a sub-section of the appsettings.json file
services.Configure<MySubOptions>(Configuration.GetSection("subsection"));//手动高亮
// Add framework services.
services.AddMvc();
}
当你通过绑定选项来配置选项类型的每一个属性,实际上是绑定到每一个配置键(比如 property:subproperty:...
)。比方说,MyOptions.Option1
属性绑定到键 Option1
,那么就会从 appsettings.json 中读取 option1
属性。注意,配置键是大小写不敏感的。
通过调用 Configure<TOption>
将一个 IConfigureOptions<TOption>
服务加入服务容器,是为了之后应用程序或框架能通过 IOptions<TOption>
服务来获取配置选项。若是想从其他途径(比如之前从数据库)获取配置,你可使用 ConfigureOptions<TOptions>
扩展方法直接指定经过定制的 IConfigureOptions<TOption>
服务。
同一个选项类型可以有多个 IConfigureOptions<TOption>
服务,届时将按顺序应用。在上例中,Option1 和 Option2 都在 appsettings.json
中指定,但 Option1 的值最后被配置委托所覆盖。
编写自定义提供程序
除使用内建的配置提供程序,你也可自行定制。为此,你只需从 ConfigurationProvider
继承并使用来自你配置提供程序的配置来填充 Data
属性即可。
例子:Entity Framework 设置
你或许希望将应用程序的配置保存在数据库中,然后通过 EntityFramework(EF)来访问它们。保存这些配置值有很多办法可以选择,比方说一张简易表格,一列表示配置名、另一列表示配置的值。在本例中,我将创建一个简易的配置提供程序,通过 EF 从数据库中读取名值对(name-value pair)。
在开始之前我们先定义一个简单的 ConfigurationValue
实体模型用来表示存储在数据库中的配置值。
public class ConfigurationContext : DbContext
{
public ConfigurationContext(DbContextOptions options) : base(options)
{
}
public DbSet<ConfigurationValue> Values { get; set; } //手动高亮
}
然后需要一个 ConfigurationContext
用来通过 EF 存储和访问配置值
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
namespace CustomConfigurationProvider
{
public class EntityFrameworkConfigurationSource : IConfigurationSource //手动高亮
{
private readonly Action<DbContextOptionsBuilder> _optionsAction;
public EntityFrameworkConfigurationSource(Action<DbContextOptionsBuilder> optionsAction)
{
_optionsAction = optionsAction;
}
public IConfigurationProvider Build(IConfigurationBuilder builder) //手动高亮
{ //手动高亮
return new EntityFrameworkConfigurationProvider(_optionsAction); //手动高亮
} //手动高亮
}
}
接着,通过继承 ConfigurationProvider
创建一个定制的配置提供程序。配置数据由重写的 Load
方法(该方法将从配置数据库中读取所有配置数据)所提供。由于这是演示,所以配置提供程序需要自行初始化数据库(如果该数据库尚未创建并初始化)
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
namespace CustomConfigurationProvider
{
public class EntityFrameworkConfigurationProvider : ConfigurationProvider //手动高亮
{
public EntityFrameworkConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
{
OptionsAction = optionsAction;
}
Action<DbContextOptionsBuilder> OptionsAction { get; }
public override void Load() //手动高亮
{ //手动高亮
var builder = new DbContextOptionsBuilder<ConfigurationContext>(); //手动高亮
OptionsAction(builder); //手动高亮
using (var dbContext = new ConfigurationContext(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(
ConfigurationContext dbContext)
{
var configValues = new Dictionary<string, string>
{
{ "key1", "value_from_ef_1" }, //手动高亮
{ "key2", "value_from_ef_2" } //手动高亮
};
dbContext.Values.AddRange(configValues
.Select(kvp => new ConfigurationValue { Id = kvp.Key, Value = kvp.Value })
.ToArray());
dbContext.SaveChanges();
return configValues;
}
}
}
按惯例,我们同样可以添加一个 AddEntityFramework
扩展方法来增加配置提供程序:
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
namespace CustomConfigurationProvider
{
public static class EntityFrameworkExtensions
{
public static IConfigurationBuilder AddEntityFrameworkConfig( //手动高亮
this IConfigurationBuilder builder, Action<DbContextOptionsBuilder> setup)
{
return builder.Add(new EntityFrameworkConfigurationSource(setup));
}
}
}
在下例中将演示如何在应用程序中使用此定制的 ConfigurationProvider
。创建一个新的 [ConfigurationBuilder][ConfigurationBuilder1]
来设置配置提供程序。指定数据提供程序和连接字符串后,添加 EntityFrameworkConfigurationProvider
配置提供程序。那你如何配置连接字符串呢?当然也是使用配置了!添加 appsettings.json 作为配置提供者来引导建立 EntityFrameworkConfigurationProvider
。通过重用相同的 ConfigurationBuilder
,在数据库中指定的任何配置都将覆盖 appsettings.json 中所指定的对应设置:
using System;
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
namespace CustomConfigurationProvider
{
public static class Program
{
public static void Main()
{
// work with with a builder using multiple calls
var builder = new ConfigurationBuilder();
builder.SetBasePath(Directory.GetCurrentDirectory());
builder.AddJsonFile("appsettings.json");
var connectionStringConfig = builder.Build();
// chain calls together as a fluent API
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json") //手动高亮
.AddEntityFrameworkConfig(options => //手动高亮
options.UseSqlServer(connectionStringConfig.GetConnectionString("DefaultConnection")) //手动高亮
) //手动高亮
.Build();
Console.WriteLine("key1={0}", config["key1"]);
Console.WriteLine("key2={0}", config["key2"]);
Console.WriteLine("key3={0}", config["key3"]);
}
}
}
运行程序,看到所配置的值。
总结
ASP.NET Core 提供了非常灵活的配置模型,支持多种配置文件类型、命令行、内存和环境变量。它能与配置模型无缝协作,因此你可为你的应用程序或框架注入强类型配置。你也可以创建自己定制的配置提供程序,用于协同或取代内置提供程序,保证了最大程序的灵活性。
ASP.NET Core 中文文档 第三章 原理(7)配置的更多相关文章
- ASP.NET Core 中文文档 第三章 原理(6)全球化与本地化
原文:Globalization and localization 作者:Rick Anderson.Damien Bowden.Bart Calixto.Nadeem Afana 翻译:谢炀(Kil ...
- ASP.NET Core 中文文档 第三章 原理(1)应用程序启动
原文:Application Startup 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:谢炀(kiler398).许登洋(Seay) ASP.NET Core 为你的应用程 ...
- ASP.NET Core 中文文档 第三章 原理(13)管理应用程序状态
原文:Managing Application State 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:高嵩 在 ASP.NET Core 中,有多种途径可以对应用程序的状态进行 ...
- ASP.NET Core 中文文档 第三章 原理(2)中间件
原文:Middleware 作者:Steve Smith.Rick Anderson 翻译:刘怡(AlexLEWIS) 校对:许登洋(Seay) 章节: 什么是中间件 用 IApplicationBu ...
- ASP.NET Core 中文文档 第三章 原理(3)静态文件处理
原文:Working with Static Files 作者:Rick Anderson 翻译:刘怡(AlexLEWIS) 校对:谢炀(kiler398).许登洋(Seay).孟帅洋(书缘) 静态文 ...
- ASP.NET Core 中文文档 第三章 原理(10)依赖注入
原文:Dependency Injection 作者:Steve Smith 翻译:刘浩杨 校对:许登洋(Seay).高嵩 ASP.NET Core 的底层设计支持和使用依赖注入.ASP.NET Co ...
- ASP.NET Core 中文文档 第三章 原理(11)在多个环境中工作
原文: Working with Multiple Environments 作者: Steve Smith 翻译: 刘浩杨 校对: 孟帅洋(书缘) ASP.NET Core 介绍了支持在多个环境中管 ...
- ASP.NET Core 中文文档 第三章 原理(17)为你的服务器选择合适版本的.NET框架
原文:Choosing the Right .NET For You on the Server 作者:Daniel Roth 翻译:王健 校对:谢炀(Kiler).何镇汐.许登洋(Seay).孟帅洋 ...
- ASP.NET Core 中文文档 第三章 原理(8)日志
原文:Logging 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:何镇汐.许登洋(Seay) ASP.NET Core 内建支持日志,也允许开发人员轻松切换为他们想用的其他日 ...
随机推荐
- .NET 基础 一步步 一幕幕[面向对象之构造函数、析构函数]
构造函数.析构函数 构造函数: 语法: //无参的构造函数 [访问修饰符] 函数名() :函数名必须与类名相同. //有参的构造函数 [访问修饰符] 函数名(参数列表):函数名必须与类名相同. 作用: ...
- iOS逆向工程之Hopper+LLDB调试第三方App
LLDB是Low Level Debugger的简称,在iOS开发的调试中LLDB是经常使用的,LLDB是Xcode内置的动态调试工具.使用LLDB可以动态的调试你的应用程序,如果你不做其他的额外处理 ...
- Angular2开发笔记
Problem 使用依赖注入应该注意些什么 服务一般用来做什么 指令一般用来做什么 angular2如何提取公共组件 angular2为什么不需要提公共组件 父组件与子组件之间如何通讯 什么时候应该使 ...
- [C#] C# 知识回顾 - 表达式树 Expression Trees
C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...
- Oracle 数据库知识汇总篇
Oracle 数据库知识汇总篇(更新中..) 1.安装部署篇 2.管理维护篇 3.数据迁移篇 4.故障处理篇 5.性能调优篇 6.SQL PL/SQL篇 7.考试认证篇 8.原理体系篇 9.架构设计篇 ...
- VS2015在创建项目时的一些注意事项
一.下面是在创建一个新的项目是我最常用的,现在对他们一一做一个详细的介绍: 1.Win32控制台应用程序我平时编写小的C/C++程序都用它,它应该是用的最多的. 2.名称和解决方案名称的区别:名称是项 ...
- 浅谈java异常[Exception]
学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:589809992 我们一起学Java! 一. 异常的定义 在<java编程思想 ...
- IOS开发基础知识--碎片51
1:https关闭证书跟域名的验证 AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy]; securityPolic ...
- Mysql - 游标/动态sql/事务
游标这个在我目前的项目里面用的还不多, 但是其功能还是很强大的. 动态sql以前都没用过, 是跟着富士康(不是张全蛋的富土康哦)过来的同事学的. 还是挺好用的. 我的数据库方面, 跟他学了不少. 在此 ...
- React 其实比 MVVM 架构更加卡顿
React 号称通过引入 Virtual DOM 带来了性能的提升,而其实 React 之所以需要 Virtual DOM,是因为它的架构下,state 的变更是全量的,然后触发 render 返回全 ...