原文:Configuration

作者:Steve SmithDaniel 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)配置的更多相关文章

  1. ASP.NET Core 中文文档 第三章 原理(6)全球化与本地化

    原文:Globalization and localization 作者:Rick Anderson.Damien Bowden.Bart Calixto.Nadeem Afana 翻译:谢炀(Kil ...

  2. ASP.NET Core 中文文档 第三章 原理(1)应用程序启动

    原文:Application Startup 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:谢炀(kiler398).许登洋(Seay) ASP.NET Core 为你的应用程 ...

  3. ASP.NET Core 中文文档 第三章 原理(13)管理应用程序状态

    原文:Managing Application State 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:高嵩 在 ASP.NET Core 中,有多种途径可以对应用程序的状态进行 ...

  4. ASP.NET Core 中文文档 第三章 原理(2)中间件

    原文:Middleware 作者:Steve Smith.Rick Anderson 翻译:刘怡(AlexLEWIS) 校对:许登洋(Seay) 章节: 什么是中间件 用 IApplicationBu ...

  5. ASP.NET Core 中文文档 第三章 原理(3)静态文件处理

    原文:Working with Static Files 作者:Rick Anderson 翻译:刘怡(AlexLEWIS) 校对:谢炀(kiler398).许登洋(Seay).孟帅洋(书缘) 静态文 ...

  6. ASP.NET Core 中文文档 第三章 原理(10)依赖注入

    原文:Dependency Injection 作者:Steve Smith 翻译:刘浩杨 校对:许登洋(Seay).高嵩 ASP.NET Core 的底层设计支持和使用依赖注入.ASP.NET Co ...

  7. ASP.NET Core 中文文档 第三章 原理(11)在多个环境中工作

    原文: Working with Multiple Environments 作者: Steve Smith 翻译: 刘浩杨 校对: 孟帅洋(书缘) ASP.NET Core 介绍了支持在多个环境中管 ...

  8. ASP.NET Core 中文文档 第三章 原理(17)为你的服务器选择合适版本的.NET框架

    原文:Choosing the Right .NET For You on the Server 作者:Daniel Roth 翻译:王健 校对:谢炀(Kiler).何镇汐.许登洋(Seay).孟帅洋 ...

  9. ASP.NET Core 中文文档 第三章 原理(8)日志

    原文:Logging 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:何镇汐.许登洋(Seay) ASP.NET Core 内建支持日志,也允许开发人员轻松切换为他们想用的其他日 ...

随机推荐

  1. 【.net 深呼吸】程序集的热更新

    当一个程序集被加载使用的时候,出于数据的完整性和安全性考虑,程序集文件(在99.9998%的情况下是.dll文件)会被锁定,如果此时你想更新程序集(实际上是替换dll文件),是不可以操作的,这时你得把 ...

  2. 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法

    若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...

  3. 代码的坏味道(16)——纯稚的数据类(Data Class)

    坏味道--纯稚的数据类(Data Class) 特征 纯稚的数据类(Data Class) 指的是只包含字段和访问它们的getter和setter函数的类.这些仅仅是供其他类使用的数据容器.这些类不包 ...

  4. C# 用SoapUI调试WCF服务接口(WCF中包含用户名密码的验证)

    问题描述: 一般调试wcf程序可以直接建一个单元测试,直接调接口. 但是,这次,我还要测试在接口内的代码中看接收到的用户名密码是否正确,所以,单一的直接调用接口方法行不通, 然后就想办法通过soapU ...

  5. iOS 多线程之GCD的使用

    在iOS开发中,遇到耗时操作,我们经常用到多线程技术.Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法,只需定义想要执行的任务,然后添加到适当的调度队列 ...

  6. swift开发新项目总结

    新项目用swift3.0开发,现在基本一个月,来总结一下遇到的问题及解决方案   1,在确定新项目用swift后,第一个考虑的问题是用纯swift呢?还是用swift跟OC混编      考虑到新项目 ...

  7. Xamarin Android 应用程序内图标上数字提示

    最近在用 Xamarin 做一个 Android 应用,打开应用时,如果有新消息,需要在应用内的 Toolbar 或者首页的图标上显示数字提示.在这里和大家分享一下实现方法,如果你有更新好的实现方法, ...

  8. 1.Hibernate简介

    1.框架简介: 定义:基于java语言开发的一套ORM框架: 优点:a.方便开发;           b.大大减少代码量;           c.性能稍高(不能与数据库高手相比,较一般数据库使用者 ...

  9. Oracle 用Drapper进行like模糊传参查询需要在参数值前后带%符合

    Oracle 用Drapper进行like模糊传参查询需要在参数值前后带%符合   string sqlstr="select * from tblname where name like ...

  10. Java集合---ConcurrentHashMap原理分析

    集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).这篇文章主 ...