不管是.net还是.netcore项目,我们都少不了要读取配置文件,在.net中项目,配置一般就存放在web.config中,但是在.netcore中我们新建的项目根本就看不到web.config,取而代之的是appsetting.json。

新建一个webapi项目,可以在startup中看到一个IConfiguration,通过框架自带的IOC使用构造函数进行实例化,在IConfiguration中我们发现直接就可以读取到appsetting.json中的配置项了,如果在控制器中需要读取配置,也是直接通过构造

函数就可以实例化IConfiguration对象进行配置的读取。下面我们试一下运行的效果,在appsetting.json添加一个配置项,在action中可以进行访问。

添加其他配置文件

那我们的配置项是不是只能写在appsetting.json中呢?当然不是,下面我们看看如何添加其他的文件到配置项中,根据官网教程,我们可以使用ConfigureAppConfiguration实现。

首先我们在项目的根目录新建一个config.json,然后在其中随意添加几个配置,然后在program.cs中添加高亮显示的部分,这样很简单的就将我们新增的json文件中的配置加进来了,然后在程序中就可以使用IConfiguration进行访问config.json

中的配置项了。

public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
} public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(configure => {
configure.AddJsonFile("config.json"); //无法热修改 })
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}

但是这个无法在配置项修改后读取到最新的数据,我们可以调用重载方法configure.AddJsonFile("config.json",true,reloadOnChange:true)实现热更新。

除了添加json文件外,我们还可以使用AddXmlFile添加xml文件,使用AddInMemoryCollection添加内存配置

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context,configure) => {
Dictionary<string, string> memoryConfig = new Dictionary<string, string>();
memoryConfig.Add("memoryKey1", "m1");
memoryConfig.Add("memoryKey2", "m2"); configure.AddInMemoryCollection(memoryConfig); })
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});

源码解读:

在自动生成的项目中,我们没有配置过如何获取配置文件,那.netcore框架是怎么知道要appsetting.json配置文件的呢?我们通过查看源码我们就可以明白其中的道理。

Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
}); //CreateDefaultBuilder源码
public static IHostBuilder CreateDefaultBuilder(string[] args)
{
var builder = new HostBuilder(); builder.UseContentRoot(Directory.GetCurrentDirectory());
builder.ConfigureHostConfiguration(config =>
{
config.AddEnvironmentVariables(prefix: "DOTNET_");
if (args != null)
{
config.AddCommandLine(args);
}
}); builder.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment; config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName))
{
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
if (appAssembly != null)
{
config.AddUserSecrets(appAssembly, optional: true);
}
} config.AddEnvironmentVariables(); if (args != null)
{
config.AddCommandLine(args);
}
}); .... return builder;
}

怎么样?是不是很有意思,在源码中我们看到在Program中构建host的时候就会调用ConfigureAppConfiguration对应用进行配置,会读取appsetting.json文件,并且会根据环境变量加载不同环境的appsetting,同时还可以看到应用不仅添加了

appsetting的配置,而且添加了从环境变量、命令行传入参数的支持,对于AddUserSecrets支持读取用户机密文件中的配置,这个在存储用户机密配置的时候会用到。

那为什么我们可以通过再次调用ConfigureAppConfiguration去追加配置信息,而不是覆盖呢?我们同样可以在源码里面找到答案。

public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

//以下为部分源码
private List<Action<HostBuilderContext, IConfigurationBuilder>> _configureAppConfigActions = new List<Action<HostBuilderContext, IConfigurationBuilder>>();
private IConfiguration _appConfiguration; public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate)
{
_configureAppConfigActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)));
return this;
} public IHost Build()
{
... BuildAppConfiguration(); ...
} private void BuildAppConfiguration()
{
var configBuilder = new ConfigurationBuilder()
.SetBasePath(_hostingEnvironment.ContentRootPath)
.AddConfiguration(_hostConfiguration, shouldDisposeConfiguration: true); foreach (var buildAction in _configureAppConfigActions)
{
buildAction(_hostBuilderContext, configBuilder);
}
_appConfiguration = configBuilder.Build();
_hostBuilderContext.Configuration = _appConfiguration;
}

框架声明了一个List<Action<HostBuilderContext, IConfigurationBuilder>>,我们每次调用ConfigureAppConfiguration都是往这个集合中添加元素,等到Main函数调用Build的时候会触发ConfigurationBuilder,将集合中的所有元素进行循环追加

到ConfigurationBuilder,最后就形成了我们使用的IConfiguration,这样一看对于.netcore中IConfiguration是怎么来的就很清楚了。

读取层级配置项

如果需要读取配置文件中某个层级的配置应该怎么做呢?也很简单,使用IConfiguration["key:childKey..."]

比如有这样一段配置:

"config_key2": {
"config_key2_1": "config_key2_1",
"config_key2_2": "config_key2_2"
}

可以使用IConfiguration["config_key2:config_key2_1"]来获取到config_key2_1的配置项,如果config_key2_1下还有子配置项childkey,依然可以继续使用:childkey来获取

选项模式获取配置项

选项模式使用类来提供对相关配置节的强类型访问,将配置文件中的配置项转化为POCO模型,可为开发人员编写代码提供更好的便利和易读性

我们添加这样一段配置:

"Student": {
"Sno": "SNO",
"Sname": "SNAME",
"Sage": 18,
"ID": "001"
}

接下来我们定义一个Student的Model类

public class Student
{
private string _id;
public const string Name = "Student";
private string ID { get; set; }
public string Sno { get; set; }
public string Sname { get; set; }
public int Sage { get; set; }
}

可以使用多种方式来进行绑定:

1、使用Bind方式绑定

Student student = new Student();
_configuration.GetSection(Student.Name).Bind(student);

2、使用Get方式绑定

var student1 = _configuration.GetSection(Student.Name).Get<Student>(binderOptions=> {
  binderOptions.BindNonPublicProperties = true;
});

Get方式和Bind方式都支持添加一个 Action<BinderOptions>的重载,通过这个我们配置绑定时的一些配置,比如非公共属性是否绑定(默认是不绑定的),但是Get比BInd使用稍微方便一些,如果需要绑定集合也是一样的道理,将Student

替换成List<Student>。

3、全局方式绑定

前两种方式只能在局部生效,要想做一次配置绑定,任何地方都生效可用,我们可以使用全局绑定的方式,全局绑定在Startup.cs中定义

services.Configure<Student>(Configuration.GetSection(Student.Name));

此方式会使用选项模式进行配置绑定,并且会注入到IOC中,在需要使用的地方可以在构造函数中进行实例化

private readonly ILogger<WeatherForecastController> _logger;
private readonly IConfiguration _configuration;
private readonly Student _student; public WeatherForecastController(ILogger<WeatherForecastController> logger, IConfiguration configuration, IOptions<Student> student)
{
_logger = logger;
_configuration = configuration;
_student = student.Value;
}

 

命名选项的使用

对于不同的配置节,包含的配置项一样时,我们在使用选项绑定的时候无需定义和注入两个类,可以在绑定时指定名称,比如下面的配置:

"Root": {
"child1": {
"child_1": "child1_1",
"child_2": "child1_2"
},
"child2": {
"child_1": "child2_1",
"child_2": "child2_2"
}
}

public class Root
{
  public string child_1{get;set;}
  public string child_2{get;set;}
} services.Configure<Root>("Child1",Configuration.GetSection("Root:child1"));
services.Configure<Root>("Child2", Configuration.GetSection("Root:child2")); private readonly ILogger<WeatherForecastController> _logger;
private readonly IConfiguration _configuration;
private readonly Student _student;
private readonly Root _child1;
private readonly Root _child2; public WeatherForecastController(ILogger<WeatherForecastController> logger, IConfiguration configuration, IOptions<Student> student,IOptionsSnapshot<Root> root)
{
_logger = logger;
_configuration = configuration;
_student = student.Value;
_child1 = root.Get("Child1");
_child2 = root.Get("Child2");
}

浅析.netcore中的Configuration的更多相关文章

  1. netcore中的缓存介绍

    Cache(缓存)是优化web应用的常用方法,缓存存放在服务端的内存中,被所有用户共享.由于Cache存放在服务器的内存中,所以用户获取缓存资源的速度远比从服务器硬盘中获取快,但是从资源占有的角度考虑 ...

  2. 浅析JDK中ServiceLoader的源码

    前提 紧接着上一篇<通过源码浅析JDK中的资源加载>,ServiceLoader是SPI(Service Provider Interface)中的服务类加载的核心类,也就是,这篇文章先介 ...

  3. .netcore 中使用开源的AOP框架 AspectCore

    AspectCore Project 介绍 什么是AspectCore Project ? AspectCore Project 是适用于Asp.Net Core 平台的轻量级 Aop(Aspect- ...

  4. .NetCore中简单使用EasyNetQ

    前言 我们在.Net中使用RabbitMQ,最原始的就是基于RabbitMQ.Client进行编码,在这个过程中我们需要通过代码约定和维护队列,Exchange等.如果是自行编码封装通用型的Rabbi ...

  5. Asp.NetCore 中Aop的应用

    前言 其实好多项目中,做一些数据拦截.数据缓存都有Aop的概念,只是实现方式不一样:之前大家可能都会利用过滤器来实现Aop的功能,如果是Asp.NetCore的话,也可能会使用中间件: 而这种实现方式 ...

  6. 【Elasticsearch】.NetCore中Elasticsearch组件NEST的使用

    .NetCore中Elasticsearch组件NEST的使用 1. 安装Docker # 安装Docker curl -fsSL https://get.docker.com | bash -s d ...

  7. Consul+Ocelot+Polly在.NetCore中使用(.NET5)-网关Ocelot+Consul

    相关文章 Consul+Ocelot+Polly在.NetCore中使用(.NET5)-Consul服务注册,服务发现 Consul+Ocelot+Polly在.NetCore中使用(.NET5)-网 ...

  8. Consul+Ocelot+Polly在.NetCore中使用(.NET5)-Ocelot+Polly缓存、限流、熔断、降级

    相关文章 Consul+Ocelot+Polly在.NetCore中使用(.NET5)-Consul服务注册,服务发现 Consul+Ocelot+Polly在.NetCore中使用(.NET5)-网 ...

  9. .NetCore中的日志(2)集成第三方日志工具

    .NetCore中的日志(2)集成第三方日志工具 0x00 在.NetCore的Logging组件中集成NLog 上一篇讨论了.NetCore中日志框架的结构,这一篇讨论一下.NetCore的Logg ...

随机推荐

  1. Git 使用,本地项目上传到GitHub远程库

    Git 使用,本地项目上传到GitHub远程库 环境 GitHub账号 点此进入github官网 git客户端工具 点此进入git下载页 本地项目上传到 GitHub 在GitHub中创建一个仓库(远 ...

  2. 【基因组注释】ncRNA注释

    目录 1. ncRNA 2. 软件 tRNA注释 rRNA注释 其他ncRNA注释 3. 注释 tRNA rRNA snRNA.miRNA等 4. snRNA.miRNA等结果的统计 1. ncRNA ...

  3. 中小型企业SaaS行业将崛起于新十年

    2020开始的新十年,国内中小型企业SaaS市场将迎来蓬勃生机,四大助推器已经就绪 第一,云服务打好底座: 随着阿里云.腾讯云乃至华为云的蓬勃发展,基础设施的不断完善,为中小型Saas企业的发展,提供 ...

  4. Linux 参数代换 命令 xargs

    xargs 命令也是管道命令中的一员.xargs命令的功能简单来说就是参数代换.那么什么叫做参数代换,这里首先要了解管道的概念.在 linux管道 命令一节中我们详细介绍了管道命令的概念.这里我们只是 ...

  5. ache

    ache和pain可能没啥差别,头疼和头好痛都对.从词典来看,有backache, bellyache, earache, headache, heartache, moustache/mustach ...

  6. Flume(二)【入门】

    目录 一.安装部署 1.安装地址 2.安装步骤 二.入门案例 1.官方案例(nestat->logger) 2.实时监控单个追加文件(exec->hdfs) 3.实时监控目录下多个新文件( ...

  7. 修改 Gradle 插件(Plugins)的下载地址(repositories)

    Gradle 也可以用下面的方式声明使用的插件: 1234 // build.gradleplugins { id 'com.example.plugin', version '1.0'} 其实是从 ...

  8. 【Linux】【Services】【Disks】bftfs

    1. 简介 1.1 Btrfs(B-tree,Butter FS,Better FS) 1.2. 遵循GPL,由oracle在2007年研发,支持CoW 1.3. 主要为了替代早期的ext3/ext4 ...

  9. Spring boot 配置文件默认放置位置,和加载优先级

    一 .默认配置文件目录 spring boot 启动会扫描以下位置的application.properties 或者application.yml文件作为spring boot 的默认配置文件 ,加 ...

  10. C++易错小结

    C++ 11 vector 遍历方法小结 方法零,对C念念不舍的童鞋们习惯的写法: void ShowVec(const vector<int>& valList) { int c ...