4.2 多级可换源的配置(下)

前面已经实现了Json配置源的方式,以及在Startup中注册使用我们的配置源。下面我们进入重点,就是如何实现数据库方式的配置。数据表对应的实体类和DbContext代码如下,就不写数据表的结构了:)

 1     public class ConfigurationSectionInfo
 2     {
 3         public string AppCode { get; set; }
 4         public string SectionCode { get; set; }
 5         public string SectionName { get; set; }
 6         public string SectionString { get; set; }
 7     }
 8
 9     public class ConfigurationContext : DbContext
10     {
11         public ConfigurationContext(DbContextOptions options) : base(options)
12         {
13         }
14
15         public DbSet<ConfigurationSectionInfo> ConfigurationSections { get; set; }
16
17         protected override void OnModelCreating(ModelBuilder modelBuilder)
18         {
19             EntityTypeBuilder<ConfigurationSectionInfo> builder = modelBuilder.Entity<ConfigurationSectionInfo>();
20
21             builder.ToTable("CONFIGURATION_SECTION_INFO");
22             builder.Property(c => c.AppCode).HasColumnName("APP_CODE").IsRequired();
23             builder.Property(c => c.SectionCode).HasColumnName("SECTION_CODE").IsRequired();
24             builder.Property(c => c.SectionName).HasColumnName("SECTION_NAME").IsRequired();
25             builder.Property(c => c.SectionString).HasColumnName("SECTION_STRING").IsRequired();
26
27             builder.HasKey(c => new { c.AppCode, c.SectionCode });
28         }
29     }

接下来就是数据库的配置源类DatabaseConfigSource,继承我们自己的基类ConfigSource,并实现GetConfigurationRoot方法。

 1     [TypeName("Database", "数据库配置")]
 2     public class DatabaseConfigSource : ConfigSource
 3     {
 4         public DatabaseConfigSource(string parameter) : base(parameter)
 5         {
 6         }
 7
 8         public override IConfigurationRoot GetConfigurationRoot()
 9         {
10             AppConfigInfo config = AppConfigInfo.GetConfig();
11
12             ConfigurationBuilder builder = new ConfigurationBuilder();
13             builder.Add(new DbConfigurationSource(options => options.UseSqlServer(_Parameter), config.AppCode));
14
15             return builder.Build();
16         }
17     }

需要注意的是AppConfigInfo类,这个类我们用到的是AppCode属性,AppCode是指应用程序代码。因为我们的公共配置可以给多个应用使用,因此数据库方式获取配置时必须传入AppCode。在这里的意思是获取与应用程序(AppCode)相关的配置项。因为配置数据表中可能存在许多个应用的配置信息,我们这里只获取当前应用的配置信息。Parameter参数就是数据库链接串,可以在前面一节ConfigSource类的介绍中明显的看到。

创建ConfigurationBuilder,添加IConfigurationSource的数据库实现--DbConfigurationSource,其核心是DbConfigurationProvider。DbConfigurationSource和DbConfigurationProvider的实现如下:

 1     public class DbConfigurationSource : IConfigurationSource
 2     {
 3         private readonly Action<DbContextOptionsBuilder> _optionsAction;
 4         private readonly string appCode;
 5
 6         public DbConfigurationSource(Action<DbContextOptionsBuilder> optionsAction, string appCode)
 7         {
 8             _optionsAction = optionsAction;
 9             this.appCode = appCode;
10         }
11
12         public IConfigurationProvider Build(IConfigurationBuilder builder)
13         {
14             return new DbConfigurationProvider(_optionsAction, appCode);
15         }
16     }
17
18     public class DbConfigurationProvider : ConfigurationProvider
19     {
20         private Action<DbContextOptionsBuilder> optionsAction;
21         private string appCode;
22
23         public DbConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction, string appCode)
24         {
25             this.optionsAction = optionsAction;
26             this.appCode = appCode;
27         }
28
29         public override void Load()
30         {
31             var builder = new DbContextOptionsBuilder<ConfigurationContext>();
32             optionsAction(builder);
33
34             using (var dbContext = new ConfigurationContext(builder.Options))
35             {
36                 dbContext.Database.EnsureCreated();
37                 Data = GetConfigData(dbContext);
38             }
39         }
40
41         private IDictionary<string, string> GetConfigData(ConfigurationContext dbContext)
42         {
43             List<string> configSections = new List<string>();
44
45             var appConfigs = dbContext.ConfigurationSections.Where(a => a.AppCode == this.appCode);
46             foreach (ConfigurationSectionInfo info in appConfigs)
47             {
48                 configSections.Add("\"" + info.SectionCode + "\":{" + info.SectionString + "}");
49             }
50
51             var defConfigs = dbContext.ConfigurationSections.Where(d => string.IsNullOrEmpty(d.AppCode) && appConfigs.Any(a => a.SectionCode == d.SectionCode));
52             foreach (ConfigurationSectionInfo info in defConfigs)
53             {
54                 configSections.Add("\"" + info.SectionCode + "\":{" + info.SectionString + "}");
55             }
56
57             string configs = "{\"MicroStrutLibrary\":{" + string.Join(",", configSections) + "}}";
58
59             return JsonConfigurationParser.Parse(configs);
60         }
61     }

DbConfigurationProvider程序的大体流程是:从数据库中读取与本应用(AppCode)相关的配置节,再读取所有应用为空的配置节(缺省配置节),然后所有配置节合并成为一个总的配置字符串,最后调用解析方法生成配置的Key/Value。解析的代码:

 1     public static class JsonConfigurationParser
 2     {
 3         private static IDictionary<string, string> _data;
 4         private static Stack<string> _context;
 5         private static string _currentPath;
 6
 7         static JsonConfigurationParser()
 8         {
 9             _data = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
10             _context = new Stack<string>();
11         }
12
13         public static IDictionary<string, string> Parse(string configs)
14         {
15             _data.Clear();
16
17             var jsonConfig = JObject.Parse(configs);
18
19             VisitJObject(jsonConfig);
20
21             return _data;
22         }
23
24         private static void VisitJObject(JObject jObject)
25         {
26             foreach (var property in jObject.Properties())
27             {
28                 EnterContext(property.Name);
29                 VisitProperty(property);
30                 ExitContext();
31             }
32         }
33
34         private static void VisitProperty(JProperty property)
35         {
36             VisitToken(property.Value);
37         }
38
39         private static void VisitToken(JToken token)
40         {
41             switch (token.Type)
42             {
43                 case JTokenType.Object:
44                     VisitJObject(token.Value<JObject>());
45                     break;
46
47                 case JTokenType.Array:
48                     VisitArray(token.Value<JArray>());
49                     break;
50
51                 case JTokenType.Integer:
52                 case JTokenType.Float:
53                 case JTokenType.String:
54                 case JTokenType.Boolean:
55                 case JTokenType.Bytes:
56                 case JTokenType.Raw:
57                 case JTokenType.Null:
58                     VisitPrimitive(token);
59                     break;
60                 default:
61                     MicroStrutLibraryExceptionHelper.Throw(typeof(JsonConfigurationParser).FullName, LogLevel.Error, "类型不正确!");
62                     break;
63             }
64         }
65
66         private static void VisitArray(JArray array)
67         {
68             for (int index = 0; index < array.Count; index++)
69             {
70                 EnterContext(index.ToString());
71                 VisitToken(array[index]);
72                 ExitContext();
73             }
74         }
75
76         private static void VisitPrimitive(JToken data)
77         {
78             var key = _currentPath;
79
80             MicroStrutLibraryExceptionHelper.TrueThrow(_data.ContainsKey(key), typeof(JsonConfigurationParser).FullName, LogLevel.Error, $"键值{key}重复");
81
82             _data[key] = data.ToString();
83         }
84
85         private static void EnterContext(string context)
86         {
87             _context.Push(context);
88             _currentPath = ConfigurationPath.Combine(_context.Reverse());
89         }
90
91         private static void ExitContext()
92         {
93             _context.Pop();
94             _currentPath = ConfigurationPath.Combine(_context.Reverse());
95         }
96     }

这个解析类的代码基本照.net core的源代码复制而来。

面向云的.net core开发框架目录

时间: 2024-10-29 19:06:35

4.2 多级可换源的配置(下)的相关文章

Python pip换源 创建虚拟环境 luffy项目配置(数据库bug)

目录 pip安装源 基本使用 永久配置安装源 Windows Linux 文件配置内容 虚拟环境安装 Windows Linux 使用 luffy目录重构 日志文件配置 封装项目异常处理 二次封装Response模块 路由组件配置 数据库配置 Django 2.x 一些版本pymysql兼容问题 pip安装源 基本使用 采用国内的源,加速下载模块速度 常用的pip源: -- 豆瓣:https://pypi.douban.com/simple -- 阿里:https://mirrors.aliyu

Linux换源+编译内核总结

换源: 在主机能联网的情况下 进入存放源配置的文件夹 cd /etc/yum.repos.d 备份默认源 mv ./CentOS-Base.repo ./CentOS-Base.repo.bak 使用wget下载163的源 http://mirrors.163.com/.help/centos.html wget http://mirrors.163.com/.help/CentOS6-Base-163.repo 把下载下来的文件CentOS-Base-163.repo设置为默认源 mv Cen

装hadoop的第一步,装ubuntu并换源并装jdk

如何装ubuntu,这个自己百度.具体安装网站:http://www.ubuntu.com 我安装的是ubuntu Server版本的,然后是全英文安装.所以它的源自动定位到美国 下面是如何换源的,第一个是操作.第二个是对操作的详细讲解. 1 //里面具体输入的命令,//表示注释内容,不需要管 2 sudo su -root //切换到管理员权限 3 4 vi /etc/apt/sources.list. //用vi打开sources.list 5 6 shift+: //进入命令模式这个时候会

给npm换源

为什么要换源? npm 官方站点 http://www.npmjs.org/ 并没有被墙,但是下载第三方依赖包的速度让人着急啊! 幸运的是,国内有几个镜像站点可以供我们使用,本人在使用 http://www.cnpmjs.org/ 速度非常快,镜像站会实时更新,为我们节省了好多时间.如何给本机换源呢? (1)通过 config 配置指向国内镜像源 npm config set registry http://registry.cnpmjs.org //配置指向源 npm info express

pip和apt-get换源

pip换源 一下方法对pip和pip3同时起作用 永久换源 运行一下命令: cd ~/.pip 如果提示目录不存在的话,我们要自行创建一个,再进入目录 mkdir ~/.pip cd ~/.pip 在.pip目录下创建一个pip.conf文件 touch pip.conf 编辑pip.conf文件 sudo gedit ~/.pip/pip.conf 打开pip.conf文件窗口,将以下内容复制到文件中: [global] timeout = 6000 index-url = http://py

linux 文件目录标准,变量,修改字符集运行级别,设置别名和软件安装,(nginx),换源

# FHS 在早期的 UNIX 系统中,各个厂家各自定义了自己的 UNIX 系统文件目录,比较混乱.Linux 面世不久后,对文件目录进行了标准化,于1994年对根文件目录做了统一的规范,推出 FHS ( Filesystem Hierarchy Standard ) 的 Linux 文件系统层次结构标准.FHS 标准规定了 Linux 根目录各文件夹的名称及作用,统一了Linux界命名混乱的局面. `FHS` 是根据以往无数 Linux 用户和开发者的经验总结出来的,并且会维持更新! 无论何种

换源下载模块

换源下载模块 1.换源---清华镜像源 直接百度搜索: 清华镜像站 1.打开cmd复制清华镜像站里面网址到命令提示符里 可以临时用一次,也可以设置成永久默认源 2.pycharm配置永久第三方源: D:\Python36\Lib\site-packages\pip_internal\models\index.py 更改index.py文件中的源换成清华源 (建议使用第一种换源方法) 2.下载模块 打开cmd命令提示符直接输入pip install requests 下载requests模块 pi

drf框架, 接口(api) Django FBV =&gt; CBV drf框架的基础试图类 drf核心组件 群查与单查 python换源

接口 """ 接口概念:前台与后台进行信息交互的媒介 - url链接 接口组成: url链接 - 长得像返回数据的url链接 请求方式 - get(查).post(增).put(整体改).patch(局部改).delete(删) 请求参数 - 拼接参数.数据包参数(urlencoded.form-data.json) 响应结果 - 响应的json数据 """ 开发阶段接口测试工具 """ Postman: 官网下载.

记录和收藏一些换源的网站,以便日后复制粘贴

conda 换源 conda config --remove-key channels 换源default源 (1)清华源(TUNA) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ conda config