程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 4.2 多級可換源的配置(下),4.2可換配置

4.2 多級可換源的配置(下),4.2可換配置

編輯:關於.NET

4.2 多級可換源的配置(下),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開發框架目錄

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved