先上一段代码,了解一下 .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. Windows关机过程分析与快速关机

    原文链接:http://blog.csdn.net/flyoxs/article/details/3710367 Windows开机和关机慢,很多时候慢得令人抓狂.特别是做嵌入式开发时(如XPE和Wi ...

  2. 【BZOJ 2553】[BeiJing2011]禁忌 AC自动机+期望概率dp

    我一开始想的是倒着来,发现太屎,后来想到了一种神奇的方法——我们带着一个既有期望又有概率的矩阵,偶数(2*id)代表期望,奇数(2*id+1)代表概率,初始答案矩阵一列,1的位置为1(起点为0),工具 ...

  3. mysql共享表空间和独立表空间

    innodb这种引擎,与MYISAM引擎的区别很大.特别是它的数据存储格式等. 对于innodb的数据结构,首先要解决两个概念性的问题: 共享表空间以及独占表空间. 什么是共享表空间和独占表空间 共享 ...

  4. 关于跨域策略文件crossdomain.xml文件--配置实例

    转载自:http://bbs.phpchina.com/blog-52440-191623.html 我一直不太明白crossdomain.xml文件是干嘛用的,今天总算比较清楚的知道了一下. 这是F ...

  5. kdtree学习记录

    [转载请注明来自 Galaxies的博客:http://cnblogs.com/galaxies] 这篇文章当做一个记录啦qwq 参考:<K-D Tree在信息学竞赛中的应用>(n+e, ...

  6. python3 购物车练习

    # 购物车# 功能要求:# 要求用户输入总资产,例如:2000# 显示商品列表,让用户根据序号选择商品,加入购物车# 购买,如果商品总额大于总资产,提示账户余额不足,否则,购买成功.# 可充值.某商品 ...

  7. How to learn wxPython

    目录 How to learn wxPython Learn Python Choose a good editor Install wxPython Read the wxPython tutori ...

  8. Swift开发学习(二):Playground

    http://blog.csdn.net/powerlly/article/details/29674253 Swift开发学习:Playground 关于 对于软件用户.游戏玩家,大家一直都在提倡用 ...

  9. JAVA -- JDK JRE JAR

    转载:http://blog.csdn.net/wym19830218/article/details/5399401 JDK里面的工具也是用JAVA编写的,它们本身运行的时候也需要一套JRE,如C: ...

  10. 【洛谷P3709】大爷的字符串题

    看这题网上居然还没人写blog,怕是都去看洛谷自带的了-- 你才是字符串!你全家都是字符串!这题跟字符串没多大关系,只是出题人lxl想要吐槽某中学而已--... 其实这题说白了就是问区间里出现最多的数 ...