不管是.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. Codeforces 690A2 - Collective Mindsets (medium)

    Codeforces 题面传送门 & 洛谷题面传送门 一道脑筋急转弯的结论题. 首先我们考虑对于某个特定的金币数 \(m\),有哪些 \(n\) 满足条件.考虑最 naive 的情况,\(m= ...

  2. 一类利用队列优化的DP

    I.导入: 这是一个\(O(n^2)\)的状态和转移方程: \[f(i,j)=\left\{ \begin{aligned} f(i-1,j-1)+k \ (1\leq j)\\ \max_{k \i ...

  3. 如何根据fasta快速统计基因组大小及其各染色体长度?

    基因组长度 利用seqkit统计长度 seqkit stat test.fa 结果如下: file format type num_seqs sum_len min_len avg_len max_l ...

  4. xshell的快捷复制粘贴设置

    今天试着用xshell连接Linux,运行一些命令的时候想快点复制粘贴实现效率,却发现还要右键选择复制,再右键选择粘贴,很是麻烦. 看了一下xshell的设置,其实可以自己设置成快捷方式 以xshel ...

  5. R语言与医学统计图形-【30】流行病学数据可视化

    sjPlot包适用于社会科学.流行病学中调查数据可视化,且能和SPSS数据无缝对接(流行病学问卷调查录入Epidata软件后,都会转成SPSS格式或EXCEL格式保存). 辅助包sjmisc进行数据转 ...

  6. Mysql-单个left join 计算逻辑(一对多问题)

    BUG背景: 我们有一个订单表 和 一个 物流表 它们通过 订单ID 进行一对一的关系绑定.但是由于物流表在保存订单信息的时候没有做判断该订单是否已经有物流信息,这就变成同一个订单id在物流表中存在多 ...

  7. Oracle-distinct()用法、count(distinct( 字段A || 字段B))是什么意思?distinct多个字段

    0.distinct用法 在oracle中distinct的使用主要是在查询中去除重复出现的数据 直接在字段前加distinct关键字即可,如:select distinct 名字 from tabl ...

  8. Perl if条件判断

    Perl 条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. 条件判断常用: True         #布尔值 not True   #布尔值 ! True    ...

  9. 基于树莓派部署 code-server

    code-server 是 vscode 的服务端程序,通过部署 code-server 在服务器,可以实现 web 端访问 vscode.进而可以达到以下能力: 支持跨设备(Mac/iPad/iPh ...

  10. Hive(九)【自定义函数】

    目录 自定义函数 编程步骤 案例 需求 1.创建工程 2.导入依赖 3.创建类 4.打jar包 5.上传hive所在服务器 6.将jar添加到hive的classpath 7.创建临时函数与开发好的j ...