.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: }

作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
7月前
|
Oracle 关系型数据库 Linux
【赵渝强老师】Oracle数据库配置助手:DBCA
Oracle数据库配置助手(DBCA)是用于创建和配置Oracle数据库的工具,支持图形界面和静默执行模式。本文介绍了使用DBCA在Linux环境下创建数据库的完整步骤,包括选择数据库操作类型、配置存储与网络选项、设置管理密码等,并提供了界面截图与视频讲解,帮助用户快速掌握数据库创建流程。
637 93
|
10月前
|
关系型数据库 MySQL 数据库连接
Django数据库配置避坑指南:从初始化到生产环境的实战优化
本文介绍了Django数据库配置与初始化实战,涵盖MySQL等主流数据库的配置方法及常见问题处理。内容包括数据库连接设置、驱动安装、配置检查、数据表生成、初始数据导入导出,并提供真实项目部署场景的操作步骤与示例代码,适用于开发、测试及生产环境搭建。
475 1
|
6月前
|
开发框架 .NET C#
ASP.NET Core Blazor 路由配置和导航
大家好,我是码农刚子。本文系统介绍Blazor单页应用的路由机制,涵盖基础配置、路由参数、编程式导航及高级功能。通过@page指令定义路由,支持参数约束、可选参数与通配符捕获,结合NavigationManager实现页面跳转与参数传递,并演示用户管理、产品展示等典型场景,全面掌握Blazor路由从入门到实战的完整方案。
559 6
|
7月前
|
Ubuntu 安全 关系型数据库
安装与配置MySQL 8 on Ubuntu,包括权限授予、数据库备份及远程连接指南
以上步骤提供了在Ubuntu上从头开始设置、配置、授权、备份及恢复一个基础但完整的MySQL环境所需知识点。
831 7
|
安全 Linux 网络安全
YashanDB数据库服务端SSL连接配置
YashanDB支持通过SSL连接确保数据传输安全,需在服务端生成根证书、服务器证书及DH文件,并将根证书提供给客户端以完成身份验证。服务端配置包括使用OpenSSL工具生成证书、设置SSL参数并重启数据库;客户端则需下载根证书并正确配置环境变量与`yasc_env.ini`文件。注意:启用SSL后,所有客户端必须持有根证书才能连接,且SSL与密码认证独立运行。
|
7月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
1336 5
|
10月前
|
安全 Java 数据库
Jasypt加密数据库配置信息
本文介绍了使用 Jasypt 对配置文件中的公网数据库认证信息进行加密的方法,以提升系统安全性。主要内容包括:1. 背景介绍;2. 前期准备,如依赖导入及版本选择;3. 生成密钥并实现加解密测试;4. 在配置文件中应用加密后的密码,并通过测试接口验证解密结果。确保密码安全的同时,保障系统的正常运行。
735 3
Jasypt加密数据库配置信息
|
9月前
|
SQL XML Java
配置Spring框架以连接SQL Server数据库
最后,需要集成Spring配置到应用中,这通常在 `main`方法或者Spring Boot的应用配置类中通过加载XML配置或使用注解来实现。
701 0
|
Java 关系型数据库 MySQL
JDK、Tomcat、MariaDB数据库和Profile多环境的配置与使用
以上就是JDK、Tomcat、MariaDB数据库和Profile多环境的配置与使用的基本步骤。这些步骤可能会因为你的具体需求和环境而有所不同,但是基本的思路是一样的。希望这些信息能够帮助你更好地理解和使用这些工具。
371 17
|
Oracle 关系型数据库 Linux
YashanDB异构数据库链接配置
本指南介绍在YashanDB中配置异构数据库链接(DBLINK)的方法,特别是连接至Oracle数据库的前置要求与步骤。需确保YashanDB服务端安装plugin插件包、Oracle Instant Client及libaio库,否则可能导致错误或进程崩溃。文档还提供了Oracle Instant Client和libaio库的具体安装指导,帮助管理员顺利完成配置。