先上一段代码,了解一下 .NET Core 配置数据的结构.

新建一个 控制台项目,添加一个文件 json.json ,文件内容如下:

{
"country": "cn",
"person": {
"id": 1,
"address": {
"addName": "chengdu"
}
}
}

控制台代码:

        private static void Main(string[] args)
{
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddJsonFile(path: @"E:\xxx\my\core\VS2017\MyConfig\Demo2\json.json", optional: false, reloadOnChange: true);
IConfigurationRoot config = builder.Build();
Console.WriteLine(config["country"]);//cn
Console.WriteLine(config["person:id"]);//
Console.WriteLine(config["person:address:addname"]);//chengdu
Console.ReadKey();//修改 json.json 文件中 "id":2
Console.WriteLine(config["person:id"]);//2
Console.ReadKey();
}

AddJsonFile 方法有多个重载,上面只给出了其中一个,3个参数分别表示:
path:文件的物理路径;
optional: xml 文档是这样写的:Whether the file is optional. 该文件是否可选.true 表示可选,即如果该文件不存在,不会抛出异常,下面的所有显示都为空;false 表示不可选,即如果该文件不存在,会抛出异常.
reloadOnChange:如果文件修改了,是否重新加载.

配置提供程序

ASP.NET Core 常用的共有6种配置提供程序 :

  • 命令行配置提供程序
  • 环境变量配置提供程序
  • 文件配置提供程序
  • Key-per-file配置提供程序
  • 内存配置提供程序
  • 自定义配置提供程序

一.命令行配置提供程序 : AddCommandLine

1.新建一个 WebAPI 项目,新建一个 TestController

    [Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{ private readonly IConfiguration _config; public TestController(IConfiguration configuration)
{
_config = configuration;
} public string Get()
{
//读取配置数据中 Key 为 CommandLineKey 的值,如果没有这个 Key,则返回默认值: defaultValue
       //读取配置文件的方法后面会单独讲.
return _config.GetValue("CommandLineKey","defaultValue");
}
}

2.修改 CreateWebHostBuilder 方法

    public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
var config = new ConfigurationBuilder().AddCommandLine(args).Build();
var hostBuilder = WebHost.CreateDefaultBuilder(args);
return hostBuilder.UseConfiguration(config).UseStartup<Startup>();
}
}

3.测试:

1)不传参数

2)传入参数

传参的格式有多种:

dotnet run CommandLineKey1=Value1

dotnet run --CommandLineKey2=Value2

dotnet run --CommandLineKey3 Value3

dotnet run /CommandLineKey4=Value4

dotnet run /CommandLineKey5 Value5

此外,传入的以单横杠"-"或者双横杠"--"作为前缀的 Key 支持替换:

    public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
Dictionary<string, string> switchMapping = new Dictionary<string, string>
{
{"-key", "CommandLineKey"},
{"--key", "CommandLineKey"},
}; IConfigurationRoot config = new ConfigurationBuilder().AddCommandLine(args, switchMapping).Build();
return WebHost.CreateDefaultBuilder().UseConfiguration(config).UseStartup<Startup>();
}
}

测试图:

两种情况都会显示

实际上,在 2.X 版本,CreateDefaultBuilder(args) 方法内部已经调用了 AddCommandLine(args) 方法,我们不需要再调一次了.源码(部分)如下:

二.环境变量配置提供程序 : AddEnvironmentVariables

在 2.X 版本,CreateDefaultBuilder(args) 方法内部已经调用了 AddEnvironmentVariables() 方法,我们不需要再调一次了.源码(部分)如下:

其实,红框框起来的方法都是配置提供程序.

那么,环境变量到底有哪些呢?哪里可以看呢?

新建如下控制器:

    [Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{ private readonly IConfiguration _config; public TestController(IConfiguration configuration)
{
_config = configuration;
} public IEnumerable<KeyValuePair<string, string>> GetAll()
{
return _config.AsEnumerable();
} public string Get(string key)
{
return _config.GetValue(key, "defaultValue");
}
}

太多了,只截了其中一小部分:

我们试试查询红框标注的环境变量:

三.文件配置提供程序 : AddJsonFile , AddIniFile , AddXmlFile

以 AddJsonFile 为例讲解,其他两个都差不多.

从上面的源码截图中我们已经看到,在使用 CreateDefaultBuilder 方法初始化新的 WebHostBuilder 时,会自动调用 AddJsonFile 两次,依次从下面两个文件加载配置:

appsettings.json : 首先读取该文件.

appsettings.{Environment}.json : 再读取此文件,该文件中的配置会替代 appsettings.json 文件中的值.

示例: (红色部分是自己加的)

appsettings.json:

{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"FirstSection": {
"SecondSection": "hello world"
}
}

appsettings.{Environment}.json:

{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"FirstSection": {
"SecondSection": "fuck u"
}
}

请求结果:

下面我们来创建自己的配置文件:

在当前项目下新建一个 jsonconfig.json 文件:

{
"id": ,
"name": "wjire"
}

CreateWebHostBuilder 方法修改如下:

        public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
IWebHostBuilder hostBuilder = WebHost.CreateDefaultBuilder(args);
return hostBuilder.ConfigureAppConfiguration((context, builder) =>
{
builder.AddJsonFile(Path.Combine(context.HostingEnvironment.ContentRootPath, "jsonconfig.json"),
true, true);
}).UseStartup<Startup>();
}

图就不上了...

附:

AddIniFile 配置文件:

[section0]
key0=value
key1=value
[section1]
subsection:key=value
[section2:subsection0]
key=value
[section2:subsection1]
key=value

AddXmlFile 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<section0>
<key0>value</key0>
<key1>value</key1>
</section0>
<section1>
<key0>value</key0>
<key1>value</key1>
</section1>
</configuration>

四.Key-per-file 配置提供程序  AddKeyPerFile

这个提供程序有点特别,它是将文件名(含扩展名)作为 Key,文件内容作为 Value.

示例:

在当前项目下新建一个 filename.txt 文件,文件内容就一句话: hello world

        public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
IWebHostBuilder hostBuilder = WebHost.CreateDefaultBuilder(args);
return hostBuilder.ConfigureAppConfiguration((context, builder) =>
{
//param1:文件所在目录的物理路径
//param2:该文件是否可选
builder.AddKeyPerFile(context.HostingEnvironment.ContentRootPath, true);
}).UseStartup<Startup>();
}

控制器如下:

    [Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{ private readonly IConfiguration _config; public TestController(IConfiguration configuration)
{
_config = configuration;
} public string Get(string key)
{
return _config.GetValue(key, "defaultValue");
}
}

五. 内存配置提供程序  AddInMemoryCollection

这个很简单,直接上图:

        public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
Dictionary<string, string> memoryCollection = new Dictionary<string, string>
{
{"id","" },
{"name","wjire" }
};
IWebHostBuilder hostBuilder = WebHost.CreateDefaultBuilder(args);
return hostBuilder.ConfigureAppConfiguration((context, builder) =>
{
builder.AddInMemoryCollection(memoryCollection);
}).UseStartup<Startup>();
}

六.自定义配置提供程序

该示例演示了如果使用EF创建从数据库(MySql)读取配置的提供程序.

第一步:安装 MySqlEF

第二步:创建数据库表:

CREATE TABLE `myconfigs` (
`Id` varchar() NOT NULL DEFAULT '',
`value` varchar() NOT NULL DEFAULT '',
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

第三步:创建实体类

    public class MyConfig
{
public string Id { get; set; } public string Value { get; set; }
}

第四步:创建数据库上下文

    public class MyConfigContext : DbContext
{
public MyConfigContext(DbContextOptions<MyConfigContext> options) : base(options)
{
} public DbSet<MyConfig> MyConfigs { get; set; }
}

第五步:创建配置数据源

    public class MyConfigSource : IConfigurationSource
{
private readonly Action<DbContextOptionsBuilder> _optionsAction; public MyConfigSource(Action<DbContextOptionsBuilder> optionsAction)
{
_optionsAction = optionsAction;
} public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new MyConfigProvider(_optionsAction);
}
}

第六步:创建配置数据源提供器

    public class MyConfigProvider : ConfigurationProvider
{
private Action<DbContextOptionsBuilder> OptionsAction { get; } public MyConfigProvider(Action<DbContextOptionsBuilder> optionsAction)
{
OptionsAction = optionsAction;
} //从数据库读取配置
public override void Load()
{
DbContextOptionsBuilder<MyConfigContext> builder = new DbContextOptionsBuilder<MyConfigContext>();
OptionsAction(builder);
using (MyConfigContext dbContext = new MyConfigContext(builder.Options))
{
//Data 是基类 ConfigurationProvider 的属性,用来存储配置数据源的.
Data = !dbContext.MyConfigs.Any()//判断表是否有数据
? CreateAndSaveDefaultValues(dbContext)//如果没有数据,则添加一些数据,存储到配置数据源中.
: dbContext.MyConfigs.ToDictionary(c => c.Id, c => c.Value);//如果有数据,读取出来,存储到配置数据源中.
}
} private static IDictionary<string, string> CreateAndSaveDefaultValues(MyConfigContext dbContext)
{
Dictionary<string, string> configValues = new Dictionary<string, string>
{
{ "", "refuge" },
{ "", "" },
{ "", "chengdu" }
};
dbContext.MyConfigs.AddRange(configValues.Select(kvp => new MyConfig
{
Id = kvp.Key,
Value = kvp.Value
}).ToArray());
dbContext.SaveChanges();
return configValues;
}
}

第七步:创建扩展方法,对外公开自定义的数据提供程序

    public static class MyConfigExtension
{
public static IConfigurationBuilder AddCustomConfigurationProviderApp(this IConfigurationBuilder builder, Action<DbContextOptionsBuilder> optionsAction)
{
return builder.Add(new MyConfigSource(optionsAction));
}
}

第八步:创建测试用的控制器

    [Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{ private readonly IConfiguration _config; public TestController(IConfiguration configuration)
{
_config = configuration;
} //查询所有
public IEnumerable<KeyValuePair<string, string>> GetAll()
{
return _config.AsEnumerable();
} //查询某个key
public string Get(string key)
{
return _config.GetValue(key, "defaultValue");
}
}

第九步:调用自定义配置提供程序

    public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{ IWebHostBuilder hostBuilder = WebHost.CreateDefaultBuilder(args);
return hostBuilder.ConfigureAppConfiguration((context, builder) =>
{
builder.AddCustomConfigurationProviderApp(options => options.UseMySql("Server=localhost;Database=test;User=root"));
}).UseStartup<Startup>();
}
}

测试结果:

1)查询所有,可以看到,我们新增的配置数据已经加到系统中了;(看右边的滚动条就知道总共有很多很多配置...)

2)查询特定key

如果使用该方式提供配置数据,需要注意以下两点:

1.提供程序在启动时就将数据库表读入配置,不会基于每个key查询数据库;

2.应用启动后,更新数据库,配置不会更新.

上面讲了如果提供配置数据,下面讲获取配置的几种常用方法:

一.GetValue 上面已经演示过了,这里不再重复.只把常用的重载方法列出来

GetValue<T>("key") 如果 key 不存在,则会抛异常;

GetValue<T>("key",T default) 如果 key 不存在,则返回默认值

二. T Get<T>()

对于下面这个 json 文件:

{
"name": "refuge",
"age": ,
"address": {
"city": "chengdu"
}
}

定义一个实体:

    public class Person
{
public string Name { get; set; } public int Age { get; set; } public Address Address { get; set; }
} public class Address
{
public string City { get; set; }
}

控制器:

    [Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{ private readonly IConfiguration _config; public TestController(IConfiguration configuration)
{
_config = configuration;
}
      public string Get()
{
var person = _config.Get<Person>();
return JsonConvert.SerializeObject(person);
}
}

调用结果:

但是这种方式,个人持反对态度,因为存储在系统中的配置数据有很多很多,上述方法相当于读取所有配置数据来反序列化.

三.GetSection

讲该方法之前,有必要再熟悉一下配置在系统中的存储结构到底是怎么样的.

对于上面那个 json 文件:name": "refuge",

"age": 36,
"address": {
"city": "chengdu"
}
}

将其读入配置后,存储的结构如下:

{"key":"name","value":"refuge"}

{"key":"age","value":"36"}

{"key":"address","value":null} //通过查询所有配置,确实有这一行,这意味着想通过 GetValue<string>("address") 反序列化为对象是不可能的...
{"key":"address:city","value":"chengdu"}]

对于上面这些配置,"refuge" 和 "36" 是可以通过第一个方法 GetValue<string>("name") , GetValue<string>("age") 来获取.

而 "chengdu" 只能用 GetValue<string>("address:city") 方法获取了.

因此,要通过该方法把上述json文件的内容转成 Person 对象,则需要对 json 文件进行修改,添加一个 "person" 节点:

{
"person": {
"name": "refuge",
"age": ,
"address": {
"city": "chengdu"
}
}
}

Action:

        public string Get()
{
//方法一:
{
Person person = _config.GetSection("person").Get<Person>();
return JsonConvert.SerializeObject(person);
} //方法二:
{
//Person person = new Person();
//_config.GetSection("person").Bind(person);
//return JsonConvert.SerializeObject(person);
}
}

方法一明显要帅气得多!

问题又来了,如果我只想反序列化 "address" 节点的值,怎么办呢?下面这个方法可以完成.

四.GetChildren

Action:

        public string Get()
{
IConfigurationSection firstChildSection = _config.GetSection("person").GetChildren().First();
Address address = firstChildSection.Get<Address>();
return JsonConvert.SerializeObject(address);
}

貌似完了.

2019年1月6日补充:

上面提到的全是从当前项目加载配置,ASP.NET Core 2.0 提供了从外部程序集加载配置的方法

需要实现该接口:

  public interface IHostingStartup
{
void Configure(IWebHostBuilder builder);
}

示例:

新建类库 : ExternalAssembly

namespace ExternalAssembly
{
public class ExternalConfig : IHostingStartup
{
public void Configure(IWebHostBuilder builder)
{
Dictionary<string, string> memoryCollection = new Dictionary<string, string>
{
{"id","" },
{"name","refuge"}
};
builder.ConfigureAppConfiguration((context, configBuilder) =>
{
configBuilder.AddInMemoryCollection(memoryCollection);
});
}
}
}

这里要特别注意:

ConfigureAppConfiguration 方法需要安装nuget包:

 

创建一个 WebAPI 项目,添加对上述类库的引用,并在 Program 类中添加对该类库的调用声明(红色标注):

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting; [assembly: HostingStartup(typeof(ExternalAssembly.ExternalConfig))] namespace Demo5
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args).UseStartup<Startup>();
}
}
}

图就不上了.

ASP.NET Core 2.2 基础知识(六) 配置(内含MySql+EF)的更多相关文章

  1. [ASP.NET Core开发实战]基础篇06 配置

    配置,是应用程序很重要的组成部分,常常用于提供信息,像第三方应用登录钥匙.上传格式与大小限制等等. ASP.NET Core提供一系列配置提供程序读取配置文件或配置项信息. ASP.NET Core项 ...

  2. ASP.NET Core 2.2 基础知识(十六) SignalR 概述

    我一直觉得学习的最好方法就是先让程序能够正常运行,才去学习他的原理,剖析他的细节. 就好像这个图: 所以,我们先跟着官方文档,创建一个 SignalR 应用: https://docs.microso ...

  3. ASP.NET Core 2.2 基础知识(十八) 托管和部署 概述

    为了方便演示,以 .NET Core 控制台应用程序讲解. 我们新建一个控制台应用程序,安装 "Newtonsoft.Json" Nuget 包,然后右键点击该项目,选择" ...

  4. ASP.NET Core 2.2 基础知识(十二) 发送 HTTP 请求

    可以注册 IHttpClientFactory 并将其用于配置和创建应用中的 HttpClient 实例. 这能带来以下好处: 提供一个中心位置,用于命名和配置逻辑 HttpClient 实例. 例如 ...

  5. ASP.NET Core 2.2 基础知识(十四) WebAPI Action返回类型(未完待续)

    要啥自行车,直接看手表 //返回基元类型 public string Get() { return "hello world"; } //返回复杂类型 public Person ...

  6. ASP.NET Core 2.2 基础知识(十三) WebAPI 概述

    我们先创建一个 WebAPI 项目,看看官方给的模板到底有哪些东西 官方给出的模板: [Route("api/[controller]")] [ApiController] pub ...

  7. ASP.NET Core 2.2 基础知识(十一) ASP.NET Core 模块

    ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ...

  8. ASP.NET Core 2.2 基础知识(十) Web服务器 - Kestrel

    ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ...

  9. ASP.NET Core 2.2 基础知识(九) 使用托管服务实现后台任务

    在 ASP.NET Core 中,后台任务作为托管服务实现.托管服务是一个类,而且必须实现 IHostedService 接口,该接口定义了两个方法: StartAsync(CancellationT ...

随机推荐

  1. SQL语言:结构化查询语言

    SQL语言:结构化查询语言 程序员或者DBA(数据库管理员)使用SQL和DBBSM进行交互,操纵数据库中的资源 分类: 1.DDL 数据定义语言 结构 create  创建   database ta ...

  2. wmic的用法

    原始文章链接:http://blog.sina.com.cn/s/blog_5fb265c70100w4d0.html 一.wmic的基本命令格式简析 经常看网上的相关资料的话,读者可能会对wmic有 ...

  3. Ubuntu下安装LNMP之nginx的安装

    Nginx 最初是作为一个 Web 服务器创建的,用于解决 C10k 的问题.作为一个 Web 服务器,它可以以惊人的速度为您的数据服务.但 Nginx 不仅仅是一个 Web 服务器,你还可以将其用作 ...

  4. python3初识selenium

    第一步:安装与配置 1.电脑上需要有火狐浏览器(默认安装在C:\Program Files (x86)\Mozilla Firefox目录下). 2.使用pip install selenium安装好 ...

  5. POJ3189:Steady Cow Assignment(二分+二分图多重匹配)

    Steady Cow Assignment Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7482   Accepted: ...

  6. Hbase写入量大导致region过大无法split问题

    最近在线上往hbase导数据,因为hbase写入能力比较强,没有太在意写的问题.让业务方进行历史数据的导入操作,中间发现一个问题,写入速度太快,并且业务数据集中到其中一个region,这个region ...

  7. ES6学习笔记(四)—— async 函数

    await 是 async wait 的简写, 是 generator 函数的语法糖. async 函数的特点: async 声明一个方法是异步的,await 则等待这个异步方法执行的完成 async ...

  8. 复选框 checkbox 选中事件

    项目中用的jquery-1.11 今天需要检测一个checkbox的选中状态,想当然的用 .attr("checked") ,结果发现,无论是否选中,这个值都是 undefined ...

  9. WEB-INF 有关的目录路径问题总结

    1.资源文件只能放在WebContent下面,如 CSS,JS,image等.放在WEB-INF下引用不了. 2.页面放在WEB-INF目录下面,这样可以限制访问,提高安全性.如JSP,html 3. ...

  10. centos 下构建lamp环境

    构建准备: 1.配置防火墙,开启80端口.3306端口 vi /etc/sysconfig/iptables -A INPUT -m state --state NEW -m tcp -p tcp - ...