.NET Core采用的全新配置系统[7]: 将配置保存在数据库中
我们在《聊聊默认支持的各种配置源》和《深入了解三种针对文件(JSON、XML与INI)的配置源》对配置模型中默认提供的各种ConfigurationSource进行了深入详尽的介绍,如果它们依然不能满足项目中的配置需求,我们可以还可以通过自定义ConfigurationProvider来支持我们希望的配置来源。就配置数据的持久化方式来说,将培植存储在数据库中应该是一种非常常见的方式,接下来我们就是创建一个针对数据库的ConfigurationSource,它采用最新的Entity Framework Core来完成数据库的存取操作。篇幅所限,我们不可能对Entity Framework Core相关的编程作单独介绍,如果读者朋友们对此不太熟悉,可以查阅Entity Framework Core在线文档。 [ 本文已经同步到《ASP.NET Core框架揭秘》之中]
目录
一、在应用中使用自定义的DbConfigurationSource
二、ApplicationSetting & ApplicationSettingsContext
三、DbConfigurationSource
四、DbConfigurationProvider
五、扩展方法AddDatabase
一、在应用中使用自定义的DbConfigurationSource
我们将这个自定义ConfigurationSource命名为DbConfigurationSource。在正式对它的实现展开介绍之前,我们先来看看它在项目中的应用。我们创建一个控制台程序来演示对这个DbConfigurationSource应用。我们将配置保存在SQL Server数据库中的某个数据表中,并采用Entity Framework Core来读取配置,所以我们需要添加针对“ Microsoft.EntityFrameworkCore”和“Microsoft.EntityFrameworkCore.SqlServer”这两个NuGet包的依赖。除此之外,我们的实例程序会采用Options模式将读取的配置绑定为了一个Options对象,所以我们添加了针对NuGet包“Microsoft.Extensions.DependencyInjection”和“Microsoft.Extensions.Options.ConfigurationExtensions”的依赖。
1: {
2: ...
3: "buildOptions": {
4: ...
5: "copyToOutput": "connectionString.json"
6: },
7:
8: "dependencies": {
9: ...
10: "Microsoft.Extensions.Options.ConfigurationExtensions" : "1.0.0",
11: "Microsoft.Extensions.DependencyInjection" : "1.0.0",
12: "Microsoft.Extensions.Configuration.Json" : "1.0.0",
13: "Microsoft.EntityFrameworkCore.SqlServer" : "1.0.0",
14: "Microsoft.EntityFrameworkCore" : "1.0.0"
15: }
16: }
我们将链接字符串作为配置定义在一个名为“connectionString.json”的JSON文件中,所以我们添加了针对NuGet包“Microsoft.Extensions.Configuration.Json”的依赖。链接字符串采用如下的形式定义在这个JSON文件中的定义,我们修改了“buildOptions/copyToOutput”配置项使这个文件可以在编译的时候可以自动拷贝到输出目录下。
1: {
2: "connectionStrings": {
3: "defaultDb": "Server = ... ; Database=...; Uid = ...; Pwd = ..."
4: }
5: }
我们编写了如下的程序来演示针对自定义ConfigurationSource(DbConfigurationSource)的应用。我们首先创建了一个ConfigurationBuilder对象,并注册了一个指向“connectionString.json”文件的JsonConfigurationSource。针对DbConfigurationSource的注册体现在扩展方法AddDatabase上,这个方法接收两个参数,它们分别代表链接字符串的名称和初始的配置数据。前者正式“connectionString.json”设置的连接字符串名称“defaultDb”,后者是一个字典对象,它提供的原始配置正好可以构成一个Profile对象。在利用ConfigurationBuilder创建出相应的Configuration对象之后,我们采用标准的Options编程模式读取配置将将其绑定为一个Profile对象。
1: var initialSettings = new Dictionary<string, string>
2: {
3: ["Gender"] = "Male",
4: ["Age"] = "18",
5: ["ContactInfo:EmailAddress"] = "foobar@outlook.com",
6: ["ContactInfo:PhoneNo"] = "123456789"
7: };
8:
9: IConfiguration config = new ConfigurationBuilder()
10: .AddJsonFile("connectionString.json")
11: .AddDatabase("DefaultDb", initialSettings)
12: .Build();
13:
14: Profile profile = new ServiceCollection()
15: .AddOptions()
16: .Configure<Profile>(config)
17: .BuildServiceProvider()
18: .GetService<IOptions<Profile>>()
19: .Value;
20:
21: Debug.Assert(profile.Gender == Gender.Male);
22: Debug.Assert(profile.Age == 18);
23: Debug.Assert(profile.ContactInfo.EmailAddress == "foobar@outlook.com");
24: Debug.Assert(profile.ContactInfo.PhoneNo == "123456789");
25:
26:
27: public class Profile
28: {
29: public Gender Gender { get; set; }
30: public int Age { get; set; }
31: public ContactInfo ContactInfo { get; set; }
32: }
33:
34: public class ContactInfo
35: {
36: public string EmailAddress { get; set; }
37: public string PhoneNo { get; set; }
38: }
39:
40: public enum Gender
41: {
42: Male,
43: Female
44: }
45:
二、ApplicationSetting & ApplicationSettingsContext
如上面的代码片断所示,针对DbConfigurationSource的应用仅仅体现在我们为ConfigurationBuilder定义的扩展方法AddDatabase上,所以使用起来是非常方便的,那么这个扩展方法背后有着怎样的逻辑实现呢?DbConfigurationSource采用Entity Framework Core以Code First的方式进行数据操作,如下所示的ApplicationSetting是表示基本配置项的POCO类型,我们将配置项的Key以小写的方式存储。另一个ApplicationSettingsContext是对应的DbContext类型。
1: [Table("ApplicationSettings")]
2: public class ApplicationSetting
3: {
4: private string key;
5:
6: [Key]
7: public string Key
8: {
9: get { return key; }
10: set { key = value.ToLowerInvariant(); }
11: }
12:
13: [Required]
14: [MaxLength(512)]
15: public string Value { get; set; }
16:
17: public ApplicationSetting()
18: {}
19:
20: public ApplicationSetting(string key, string value)
21: {
22: this.Key = key;
23: this.Value = value;
24: }
25: }
26:
27: public class ApplicationSettingsContext : DbContext
28: {
29: public ApplicationSettingsContext(DbContextOptions options) : base(options)
30: {}
31:
32: public DbSet<ApplicationSetting> Settings { get; set; }
33: }
三、DbConfigurationSource
如下所示的是DbConfigurationSource的定义,它的构造函数接受两个参数,第一个参数类型为Action<DbContextOptionsBuilder>的委托对象,我们用它来对创建DbContext采用的DbContextOptions进行设置,另一个可选的参数用来指定一些需要自动初始化的配置项。DbConfigurationSource在重写的Build方法中利用这两个对象创建一个DbConfigurationProvider对象。
1: public class DbConfigurationSource : IConfigurationSource
2: {
3: private Action<DbContextOptionsBuilder> _setup;
4: private IDictionary<string, string> _initialSettings;
5:
6: public DbConfigurationSource(Action<DbContextOptionsBuilder> setup, IDictionary<string, string> initialSettings = null)
7: {
8: _setup = setup;
9: _initialSettings = initialSettings;
10: }
11: public IConfigurationProvider Build(IConfigurationBuilder builder)
12: {
13: return new DbConfigurationProvider(_setup, _initialSettings);
14: }
15: }
四、DbConfigurationProvider
DbConfigurationProvider派生于抽象类ConfigurationProvider。在重写的Load方法中,它会根据提供的Action<DbContextOptionsBuilder>创建ApplicationSettingsContext对象,并利用后者从数据库中读取配置数据并转换成字典对象并赋值给代表配置字典的Data属性。如果数据表中没有数据,该方法还会利用这个DbContext对象将提供的初始化配置添加到数据库中。
1: public class DbConfigurationProvider: ConfigurationProvider
2: {
3: private IDictionary<string, string> _initialSettings;
4: private Action<DbContextOptionsBuilder> _setup;
5:
6: public DbConfigurationProvider(Action<DbContextOptionsBuilder> setup, IDictionary<string, string> initialSettings)
7: {
8: _setup = setup;
9: _initialSettings = initialSettings?? new Dictionary<string, string>() ;
10: }
11:
12: public override void Load()
13: {
14: DbContextOptionsBuilder<ApplicationSettingsContext> builder = new DbContextOptionsBuilder<ApplicationSettingsContext>();
15: _setup(builder);
16: using (ApplicationSettingsContext dbContext = new ApplicationSettingsContext(builder.Options))
17: {
18: dbContext.Database.EnsureCreated();
19: this.Data = dbContext.Settings.Any()? dbContext.Settings.ToDictionary(it => it.Key, it => it.Value, StringComparer.OrdinalIgnoreCase): this.Initialize(dbContext);
20: }
21: }
22:
23: private IDictionary<string, string> Initialize(ApplicationSettingsContext dbContext)
24: {
25: foreach (var item in _initialSettings)
26: {
27: dbContext.Settings.Add(new ApplicationSetting(item.Key, item.Value));
28: }
29: return _initialSettings.ToDictionary(it => it.Key, it => it.Value, StringComparer.OrdinalIgnoreCase);
30: }
31: }
五、扩展方法AddDatabase
实例演示中用来注册DbConfigurationSource的扩展方法AddDatabase具有如下的定义。该方法首先调用ConfigurationBuilder的Build方法创建出一个Configuration对象,并调用后者的扩展方法GetConnectionString根据指定的连接字符串名称得到完整的连接字符串。接下来我们调用构造函数创建一个DbConfigurationSource对象并注册到ConfigurationBuilder上。创建DbConfigurationSource对象指定的Action<DbContextOptionsBuilder>会完成针对连接字符串的设置。
1: public static class DbConfigurationExtensions
2: {
3: public static IConfigurationBuilder AddDatabase(this IConfigurationBuilder builder, string connectionStringName, IDictionary<string, string> initialSettings = null)
4: {
5: string connectionString = builder.Build().GetConnectionString(connectionStringName);
6: DbConfigurationSource source = new DbConfigurationSource(optionsBuilder => optionsBuilder.UseSqlServer(connectionString), initialSettings);
7: builder.Add(source);
8: return builder;
9: }
10: }
.NET Core采用的全新配置系统[7]: 将配置保存在数据库中的更多相关文章
- .NET Core采用的全新配置系统[10]: 配置的同步机制是如何实现的?
配置的同步涉及到两个方面:第一,对原始的配置文件实施监控并在其发生变化之后从新加载配置:第二,配置重新加载之后及时通知应用程序进而使后者能够使用最新的配置.要了解配置同步机制的实现原理,先得从认识一个 ...
- .NET Core采用的全新配置系统[2]: 配置模型设计详解
在<.NET Core采用的全新配置系统[1]: 读取配置数据>中,我们通过实例的方式演示了几种典型的配置读取方式,其主要目的在于使读者朋友们从编程的角度对.NET Core的这个全新的配 ...
- .NET Core采用的全新配置系统[3]: “Options模式”下的配置是如何绑定为Options对象
配置的原子结构就是单纯的键值对,并且键和值都是字符串,但是在真正的项目开发中我们一般不会单纯地以键值对的形式来使用配置.值得推荐的做法就是采用<.NET Core采用的全新配置系统[1]: 读取 ...
- .NET Core采用的全新配置系统[1]: 读取配置数据
提到“配置”二字,我想绝大部分.NET开发人员脑海中会立马浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化的配置定义在这两个文 ...
- .NET Core采用的全新配置系统[5]: 聊聊默认支持的各种配置源[内存变量,环境变量和命令行参数]
较之传统通过App.config和Web.config这两个XML文件承载的配置系统,.NET Core采用的这个全新的配置模型的最大一个优势就是针对多种不同配置源的支持.我们可以将内存变量.命令行参 ...
- .NET Core采用的全新配置系统[9]: 为什么针对XML的支持不够好?如何改进?
物理文件是我们最常用到的原始配置的载体,最佳的配置文件格式主要由三种,它们分别是JSON.XML和INI,对应的配置源类型分别是JsonConfigurationSource.XmlConfigura ...
- .NET Core采用的全新配置系统[8]: 如何实现配置与源文件的同步
配置的同步涉及到两个方面:第一,对原始的配置文件实施监控并在其发生变化之后从新加载配置:第二,配置重新加载之后及时通知应用程序进而使后者能够使用最新的配置.接下来我们利用一个简单的.NET Core控 ...
- 重新整理 .net core 实践篇—————配置系统之强类型配置[十]
前言 前文中我们去获取value值的时候,都是通过configurationRoot 来获取的,如configurationRoot["key"],这种形式. 这种形式有一个不好的 ...
- 虚拟机console基础环境配置——系统镜像站点配置
1. 概述2. 部署HTTP服务器2.1 YUM安装httpd2.2 配置httpd2.3 启动httpdf2.4 测试httpd3. 部署FTP服务器3.1 YUM安装vsftpd3.2 配置vsf ...
随机推荐
- 一步一步使用ABP框架搭建正式项目系列教程
研究ABP框架好多天了,第一次看到这个框架的名称到现在已经很久了,但由于当时内功有限,看不太懂,所以就只是大概记住了ABP这个名字.最近几天,看到了园友@阳光铭睿的系列ABP教程,又点燃了我内心要研究 ...
- C语言 · 判定数字
编写函数,判断某个给定字符是否为数字. 样例输入 9 样例输出 yes #include<stdio.h> int main(){ char c; scanf("%c" ...
- HDU1671——前缀树的一点感触
题目http://acm.hdu.edu.cn/showproblem.php?pid=1671 题目本身不难,一棵前缀树OK,但是前两次提交都没有成功. 第一次Memory Limit Exceed ...
- ASP.NET加密和解密数据库连接字符串
大家知道,在应用程序中进行数据库操作需要连接字符串,而如果没有连接字符串,我们就无法在应用程序中完成检索数据,创建数据等一系列的数据库操作.当有人想要获取你程序中的数据库信息,他首先看到的可能会是We ...
- 介绍一款原创的四则运算算式生成器:CalculateIt2
家里小朋友读一年级了,最近每天都有一些10以内的加减法口算练习,作为程序员爸爸,自然也是想办法能够偷懒,让电脑出题,给小朋友做些练习.于是,自己在业余时间开发了一个四则运算算式生成器,名为:Calcu ...
- .NET平台和C#编程的总结
第一章 简单认识.NET框架 (1)首先我们得知道 .NET框架具有两个主要组件:公共语言进行时CLR(Common Language Runtime)和框架类库FCL(Framework ...
- C#与C++通信
# C#与C++相互发送消息 # ## C#端: ## namespace CshapMessage { /// /// MainWindow.xaml 的交互逻辑 /// public partia ...
- WCF基础
初入职场,开始接触C#,开始接触WCF,那么从头开始学习吧,边学边补充. SOA Service-Oriented Architecture,面向服务架构,粗粒度.开放式.松耦合的服务结构,将应用程序 ...
- keepalive的不足,如何处理
MySQL(或者其它服务)的keepalived高可用监控脚本 开发脚本需求:我们知道,keepalive是基于虚拟ip的存活来判断是否抢占master的机制的,但是如果我们做了MySQL的keepa ...
- .Net程序在linux mono环境和WindowsServer上执行测试对比
最近研究了一下mono,想把windows上写的.Net程序移植到linux上跑.网上有资料说Linux上mono执行.Net程序效率比Windows高,本着实证的态度,只有实际验证过才有说服力. 写 ...