熟悉ASP.NET的开发者一定对web.config文件不陌生。在ASP.NET环境中,要想添加配置参数,一般也都会在此文件中操作。其中最常用的莫过于AppSettings与ConnectionStrings两项。而要在代码中获得文件中的配置信息,ConfigurationManager则是必不可少需要引入的程序集。

然而到了ASP.NET Core时代,存储与读取配置的方式都发生了改变。

如果对ASP.NET Core项目有所了解的话,应该会看到过appsettings.json这个文件。这里就从JSON文件配置方式开始解释ASP.NET Core中是如何读取配置信息的。

假设有预先设置的appsettings.json文件:

{
"option1": "value1_from_json",
"option2": 2, "subsection": {
"suboption1": "subvalue1_from_json"
},
"wizards": [
{
"Name": "Gandalf",
"Age": "1000"
},
{
"Name": "Harry",
"Age": "17"
}
]
}

在代码中读取可以按下面的方式操作:

public class Program
{
public static IConfiguration Configuration { get; set; } public static void Main(string[] args = null)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json"); Configuration = builder.Build(); Console.WriteLine($"option1 = {Configuration["Option1"]}");
Console.WriteLine($"option2 = {Configuration["option2"]}");
Console.WriteLine(
$"suboption1 = {Configuration["subsection:suboption1"]}");
Console.WriteLine(); Console.WriteLine("Wizards:");
Console.Write($"{Configuration["wizards:0:Name"]}, ");
Console.WriteLine($"age {Configuration["wizards:0:Age"]}");
Console.Write($"{Configuration["wizards:1:Name"]}, ");
Console.WriteLine($"age {Configuration["wizards:1:Age"]}");
Console.WriteLine(); Console.WriteLine("Press a key...");
Console.ReadKey();
}
}

首先,实例化一个ConfigurationBuilder对象,接着设置基础路径。

SetBasePath的操作其实是在ConfigurationBuilder的属性字典里设置FileProvider的值。

public static IConfigurationBuilder SetBasePath(this IConfigurationBuilder builder, string basePath)
{
... return builder.SetFileProvider(new PhysicalFileProvider(basePath));
} public static IConfigurationBuilder SetFileProvider(this IConfigurationBuilder builder, IFileProvider fileProvider)
{
... builder.Properties[FileProviderKey] = fileProvider ?? throw new ArgumentNullException(nameof(fileProvider));
return builder;
}

然后是添加JSON文件。

public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange)
{
... return builder.AddJsonFile(s =>
{
s.FileProvider = provider;
s.Path = path;
s.Optional = optional;
s.ReloadOnChange = reloadOnChange;
s.ResolveFileProvider();
});
} public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, Action<JsonConfigurationSource> configureSource)
=> builder.Add(configureSource);

ConfigurationBuilder里添加了一个JsonConfigurationSource对象。

最后,执行ConfigurationBuilder的Build方法,就可以得到保存配置信息的Configuration对象。

总结例子中的代码,获取配置信息的操作其实就分为两步:

  1. 生成Configuration对象
  2. 按键值从Configuration对象中获取信息

生成Configuration对象的步骤至少要有三个基础环节。

  1. 生成ConfigurationBuilder对象
  2. 添加ConfigurationSource对象
  3. 创建Configuration对象

查看创建Configuration对象的代码,会发现内部利用的其实是ConfigurationSource中创建的ConfigurationProvider对象。

public IConfigurationRoot Build()
{
var providers = new List<IConfigurationProvider>();
foreach (var source in Sources)
{
var provider = source.Build(this);
providers.Add(provider);
}
return new ConfigurationRoot(providers);
}

再看IConfiguratonSource接口,也只有一个Build方法。

public interface IConfigurationSource
{
IConfigurationProvider Build(IConfigurationBuilder builder);
}

最终创建的Configuration对象,即ConfigurationRoot中包含了所有的ConfigurationProvider,说明配置信息都由这些ConfigurationProvider所提供。

跟踪至ConfigurationRoot类型的构造方法,果然在其生成对象时,对所有ConfigurationProvider进行了加载操作。

public ConfigurationRoot(IList<IConfigurationProvider> providers)
{
... _providers = providers;
foreach (var p in providers)
{
p.Load();
ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged());
}
}

比如JsonConfigurationProvider中:

public override void Load(Stream stream)
{
try
{
Data = JsonConfigurationFileParser.Parse(stream);
}
...
}

通过JSON解析器,将JSON文件的配置信息读取至ConfigurationProvider的Data属性中。这个属性即是用于保存所有配置信息。

  /// <summary>
/// The configuration key value pairs for this provider.
/// </summary>
protected IDictionary<string, string> Data { get; set; }

有了ConfigurationRoot对象后,获取配置信息的操作就很简单了。遍历各个ConfigurationProvider,从中获取第一个匹配键值的数据。

public string this[string key]
{
get
{
foreach (var provider in _providers.Reverse())
{
string value; if (provider.TryGet(key, out value))
{
return value;
}
} return null;
} ...
}

ConfigurationProvider对象从Data属性获取配置的值。

public virtual bool TryGet(string key, out string value)
=> Data.TryGetValue(key, out value);

在最初的例子中可以看Configuration["wizards:0:Name"]这样的写法,这是因为在Load文件时,存储的方式就是用:为分隔符,以作为嵌套对象的键值。

也可以用另一种方法来写,将配置信息绑定为对象。

先定义对象类型:

public class AppSettings
{
public string Option1 { get; set; }
public int Option2 { get; set; }
public Subsection Subsection { get; set; }
public IList<Wizards> Wizards { get; set; }
} public class Subsection
{
public string Suboption1 { get; set; }
} public class Wizards
{
public string Name { get; set; }
public string Age { get; set; }
}

再绑定对象:

static void Main(string[] args)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json"); Configuration = builder.Build(); var appConfig = new AppSettings();
Configuration.Bind(appConfig); Console.WriteLine($"option1 = {appConfig.Option1}");
Console.WriteLine($"option2 = {appConfig.Option2}");
Console.WriteLine(
$"suboption1 = {appConfig.Subsection.Suboption1}");
Console.WriteLine(); Console.WriteLine("Wizards:");
Console.Write($"{appConfig.Wizards[0].Name}, ");
Console.WriteLine($"age {appConfig.Wizards[0].Age}");
Console.Write($"{appConfig.Wizards[1].Name}, ");
Console.WriteLine($"age {appConfig.Wizards[1].Age}");
Console.WriteLine(); Console.WriteLine("Press a key...");
Console.ReadKey();
}

写法变成了常见的对象调用属性方式,但结果是一样的。

除了可以用JSON文件存储配置信息外,ASP.NET Core同时也支持INI与XML文件。当然有其它类型文件时,也可以通过实现IConfigurationSource接口并继承ConfigurationProvider类建立自定义的ConfigrationProvider对象来加载配置文件。

至于文件以外的方式,ASP.NET Core也提供了不少。

  • 命令行,AddCommandLine
  • 环境变量,AddEnvironmentVariables
  • 内存, AddInMemoryCollection
  • 用户机密,AddUserSecrets
  • Azure Key Vault,AddAzureKeyVault

选择何种存储与读取配置的方法取决于实际场景,ASP.NET Core已经开放了配置方面的入口,任何接入方式理论上都是可行的。实践方面,则需要开发者们不断去尝试与探索。

.NET Core开发日志——配置的更多相关文章

  1. C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志

    C#实现多级子目录Zip压缩解压实例 参考 https://blog.csdn.net/lki_suidongdong/article/details/20942977 重点: 实现多级子目录的压缩, ...

  2. .NET Core开发日志——Entity Framework与PostgreSQL

    Entity Framework在.NET Core中被命名为Entity Framework Core.虽然一般会用于对SQL Server数据库进行数据操作,但其实它还支持其它数据库,这里就以Po ...

  3. .NET Core开发日志——RequestDelegate

    本文主要是对.NET Core开发日志--Middleware的补遗,但是会从看起来平平无奇的RequestDelegate开始叙述,所以以其作为标题,也是合情合理. RequestDelegate是 ...

  4. .NET Core开发日志——从搭建开发环境开始

    .NET Core自2016年推出1.0版本开始,到目前已是2.1版本,在其roadmap计划里明年更会推出3.0版本,发展不可不谓之迅捷.不少公司在经过一个谨慎的观望期后,也逐步开始将系统升级至最新 ...

  5. ASP.NET Core开发-如何配置Kestrel 网址Urls

    ASP.NET Core中如何配置Kestrel Urls呢,大家可能都知道使用UseUrls() 方法来配置. 今天给介绍全面的ASP.NET Core 配置 Urls,使用多种方式配置Urls. ...

  6. .NET Core开发日志——Linux版本的SQL Server

    SQL Server 2017版本已经可以在Linux系统上安装,但我在尝试.NET Core跨平台开发的时候使用的是Mac系统,所以这里记录了在Mac上安装SQL Server的过程. 最新的SQL ...

  7. .NET Core开发日志——简述路由

    有过ASP.NET或其它现代Web框架开发经历的开发者对路由这一名字应该不陌生.如果要用一句话解释什么是路由,可以这样形容:通过对URL的解析,指定相应的处理程序. 回忆下在Web Forms应用程序 ...

  8. django开发日志配置

    做django开发离不开 日志,这用于保存我门的服务器的日志信息,便于开发人员的维护. 直接上代码: 在setting.py文件里直接配置即可 LOGGING = { 'version': 1, 'd ...

  9. .NET Core开发日志——OData

    简述 OData,即Open Data Protocol,是由微软在2007年推出的一款开放协议,旨在通过简单.标准的方式创建和使用查询式及交互式RESTful API. 类库 在.NET Core中 ...

随机推荐

  1. ORA-16447 Redo apply was not active at the target standby database

    Cause ALTER SYSTEM FLUSH REDO TO STANDBY failed because redo apply is not active at the target datab ...

  2. Zabbix-2.X/3.X监控工具监控Redis以及zabbix Redis监控模板下载

    为了监控Redis3的运行状况,去zabbix官网查找资料,根据提示,找到了这个项目:https://github.com/blacked/zbx_redis_template 但是文档和内容已经不匹 ...

  3. HTML Entity 字符实体(字符转义)

    目录 1. HTML Entity 2. 字符与Entity Name的互相转换 3. 字符与Entity Number的互相转换 1. HTML Entity 1.1 介绍 在编写HTML页面时,需 ...

  4. python工具 - 读取文件的部分指定内容并输出到外置窗口

    一.使用场景 某些配置文件里有一些特定的字符,而这些字符恰巧需要我们采集出来,然后输出到另外一个窗口做展示时,可以使用该工具. 本例的演示则提取配置文件中的[姓名:黄蓉 女 九阴真经.姓名:郭靖 男 ...

  5. 使用vuejs做一个todolist

    在输入框内输入一个list,回车,添加到list列表中,点击列表中的项样式改变 1.index.html <!DOCTYPE html> <html> <head> ...

  6. linux每日命令(32):gzip命令

    减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间.gzip是在Linux系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用.gzip不仅可以用 ...

  7. Linux免密码登录设置 && 设置快捷键

    看到这篇文章,你肯定是有这种需求. 假设要登录的机器为192.168.1.100,当前登录的机器为192.168.1.101. 首先在101的机器上生成密钥(如果已经生成可以跳过): $ ssh-ke ...

  8. PyCharm 2018 最新激活方式总结(最新最全最有效!!!)

    PyCharm 2018 最新激活方式总结(最新最全最有效!!!) 欲善其事,必先利其器.这里我为大家提供了三种激活方式: 授权服务器激活:适合小白,一步到位,但服务器容易被封 激活码激活:适合小白, ...

  9. Extjs4.2x与富文本框编辑器KindEditor的整合

    Extjs4本身的HtmlEditor编辑器,太鸡肋了,简单的html能够应付一下,稍加复杂的就无能为力了. 对于Extjs的HtmlEditor扩展主要有三个方向,一个是扩展其本身的htmlEdit ...

  10. [js] 处理字符串换行造成的json解析失败

    需求:从数据库某个字段取出字符串出来,转为json,结果发现报错为 解析失败,发现是因为取出的字符串换行导致,现在需要将字符串里面的换行替换为'',使字符串可依成功解析成json对象. 技术:依靠re ...