自定義配置信息的高級應用 通過上篇博文對簡單的自定義配置信息的學習,使得更加靈活的控制系統配置信息。實際項目中,這種配置的靈活度往往無法滿足項目的靈活度和擴展性。 比如,一個配置信息有三部分組成,而每部分中有包括一些配置信息。僅僅使用簡單的自定義配置無法滿足,因此,需要提供更多的自定義配置方法來靈活 ...
自定義配置信息的高級應用
通過上篇博文對簡單的自定義配置信息的學習,使得更加靈活的控制系統配置信息。實際項目中,這種配置的靈活度往往無法滿足項目的靈活度和擴展性。
比如,一個配置信息有三部分組成,而每部分中有包括一些配置信息。僅僅使用簡單的自定義配置無法滿足,因此,需要提供更多的自定義配置方法來靈活實現。
針對配置信息中包括配置列表和配置項的要求,主要使用.Net Framework中的以下兩個類來實現:
ConfigurationElement:配置文件中的一個配置項
ConfigurationElementCollection:配置文件中的一個配置項集合
ConfigurationSection:配置文件中的一個配置節信息。
使用下麵的表格能夠更好說明三者之間的關係:
ConfigurationSection |
||
1:N |
ConfigurationElementCollection |
|
1:N |
ConfigurationElement <add …/> |
|
ConfigurationElement <add …/> |
||
ConfigurationElement <add …/> |
針對以上知識點,使用一個項目實例逐漸展開。
項目需求:
庫位管理系統需要實現倉庫的全方位展示,設計多種數據(SQLserver、Oracle、MySQL等),每個資料庫連接字元串的加密方式存在無法統一的情況。
配置文件的規劃:
針對以上需求,對資料庫配置文件信息的規劃為:
DBConnectionConfiguration(ConfigurationSection) |
|
||||||||||
|
ConnectionStrings(ConfigurationElementCollection) |
|
|||||||||
|
ConnectionString1(ConfigurationElement) |
|
|||||||||
name |
description |
connectionString |
providerName |
connectionDecryptName |
|
||||||
ConnectionString2(ConfigurationElement) |
|
||||||||||
name |
description |
connectionString |
providerName |
connectionDecryptName |
|||||||
DataProviders(ConfigurationElementCollection) |
|
||||||||||
|
DataProvider1(ConfigurationElement) |
|
|||||||||
name |
description |
type |
|
||||||||
DataProvider2(ConfigurationElement) |
|
||||||||||
name |
description |
type |
|
||||||||
ConnectionDecrypts(ConfigurationElementCollection) |
|
||||||||||
|
ConnectionDecrypt(ConfigurationElement) |
|
|||||||||
name |
description |
type |
|
||||||||
ConnectionDecrypt(ConfigurationElement) |
|
||||||||||
name |
description |
type |
|
配置信息實體的定義:
針對以上配置信息,先對配置信息對應的實體進行設計:
1. DBConnectionConfiguration類
它作為配置文件中的一個配置節存在,配置節名稱定義為TT.connectionManager,需要繼承自ConfigurationSection類,同時,它還需要定義三個屬性,分別是ConnectionStrings、DataProviders、ConnectionDecrypts,這三個屬性都是列表信息,因此是ConfigurationElementCollection的自定義子類。
1 /// <summary> 2 /// 資料庫連接配置信息 3 /// </summary> 4 public class DBConnectionConfiguration : ConfigurationSection 5 { 6 private const string SECION_NAME = "TT.connectionManager"; 7 8 /// <summary> 9 /// 獲取資料庫連接配置信息 10 /// </summary> 11 public static DBConnectionConfiguration GetConfig() 12 { 13 var config = ConfigurationManager.GetSection(SECION_NAME) as DBConnectionConfiguration; 14 return config; 15 } 16 17 /// <summary> 18 /// 資料庫連接字元串配置集合 19 /// </summary> 20 [ConfigurationProperty("connectionStrings")] 21 public ConnectionStringCollection ConnectionStrings 22 { 23 get 24 { 25 return (ConnectionStringCollection)base["connectionStrings"]; 26 } 27 } 28 29 /// <summary> 30 /// DataProvider配置集合 31 /// </summary> 32 [ConfigurationProperty("dataProviders", IsRequired = true)] 33 public DataProviderCollection DataProviders 34 { 35 get 36 { 37 return (DataProviderCollection)base["dataProviders"]; 38 } 39 } 40 41 /// <summary> 42 /// 連接字元串加密方式 43 /// </summary> 44 [ConfigurationProperty("connectionDecrypts", IsRequired = false)] 45 public ConnectionDecryptCollection ConnectionDecrypts 46 { 47 get 48 { 49 return (ConnectionDecryptCollection)base["connectionDecrypts"]; 50 } 51 } 52 }
2. ConnectionString類
由於定義ConfigurationElementCollection的子類時,需要使用泛型方式,定義其包含的配置項的類型,因此,先定義配置項的實體。
由於,三個不同的配置項派生類都需要在配置信息中定義名稱和描述信息來標識配置項信息,因此,提取出配置項基類,使用的配置項實體都繼承自該基類,不同的配置信息在各自類中進行自定義。
1 /// <summary> 2 /// 以名字為鍵值的配置項 3 /// </summary> 4 public class NamedConfigurationElement : ConfigurationElement 5 { 6 /// <summary> 7 /// 名稱 8 /// </summary> 9 [ConfigurationProperty("name", IsRequired = true, IsKey = true)] 10 public virtual string Name 11 { 12 get 13 { 14 return (string)this["name"]; 15 } 16 } 17 18 /// <summary> 19 /// 描述 20 /// </summary> 21 [ConfigurationProperty("description", DefaultValue = "")] 22 public virtual string Description 23 { 24 get 25 { 26 return (string)this["description"]; 27 } 28 } 29 }
以ConnectionStringElement為例,該實體定義三個屬性信息:資料庫連接字元串信息、資料庫訪問提供者、連接加密信息名稱,其中連接加密名稱填寫時,使用ConnectionDecryptCollection中的定義解密類的類型信息進行反射實例化進行解密,不填寫時則直接使用連接字元串信息。
1 /// <summary> 2 /// 連接字元串配置項 3 /// </summary> 4 public class ConnectionStringElement:NamedConfigurationElement 5 { 6 /// <summary> 7 /// 連接字元串 8 /// </summary> 9 private string _connectionString = ""; 10 11 /// <summary> 12 /// 連接字元串 13 /// </summary> 14 [ConfigurationProperty("connectionString")] 15 public string ConnectionString 16 { 17 get 18 { 19 if (!string.IsNullOrWhiteSpace(_connectionString)) 20 return _connectionString; 21 var decryptName = ConnectionDecryptName; 22 if (string.IsNullOrWhiteSpace(decryptName)) 23 _connectionString = (string)base["connectionString"]; 24 else 25 { 26 DBConnectionConfiguration config = DBConnectionConfiguration.GetConfig(); 27 var decrytType = config.ConnectionDecrypts[decryptName].Type; 28 IConnectionDecrypt cb = ReflectionHelper.CreateInstance(decrytType) as IConnectionDecrypt; 29 _connectionString = cb.Decrypt((string)base["connectionString"]); 30 } 31 return _connectionString; 32 } 33 } 34 35 /// <summary> 36 /// DataProvider名稱 37 /// </summary> 38 [ConfigurationProperty("providerName")] 39 public string ProviderName 40 { 41 get 42 { 43 return (string)base["providerName"]; 44 } 45 } 46 47 48 /// <summary> 49 /// 連接字元串加密方法名稱 50 /// </summary> 51 [ConfigurationProperty("connectionDecryptName", DefaultValue = "", IsRequired = false)] 52 public string ConnectionDecryptName 53 { 54 get 55 { 56 return (string)base["connectionDecryptName"]; 57 } 58 } 59 }
1 /// <summary> 2 /// DataProvider配置項 3 /// </summary> 4 public class DataProviderElement: NamedConfigurationElement 5 { 6 /// <summary> 7 /// DataProvider類型信息 8 /// </summary> 9 [ConfigurationProperty("type")] 10 public string Type 11 { 12 get 13 { 14 return (string)base["type"]; 15 } 16 } 17 }
1 /// <summary> 2 /// 字元串加密方式配置項 3 /// </summary> 4 public class ConnectionDecryptElement:NamedConfigurationElement 5 { 6 /// <summary> 7 /// 字元串加密方式類型信息 8 /// </summary> 9 [ConfigurationProperty("type")] 10 public string Type 11 { 12 get 13 { 14 return (string)base["type"]; 15 } 16 } 17 }
3. ConnectionStrings類
ConnectionStrings、DataProviders、ConnectionDecrypts三個配置列表實體,都會使用到使用配置項的名稱獲取對應的配置信息,因此需要將公共方法提取出來基類。
1 public abstract class NamedConfigurationElementCollection<T> : ConfigurationElementCollection 2 3 where T : NamedConfigurationElement, new() 4 5 { 6 7 /// <summary> 8 /// 按照名稱獲取指定的配置元素 9 /// </summary> 10 /// <param name="name">名稱</param> 11 /// <returns>配置元素</returns> 12 public new T this[string name] { get { return (T)BaseGet(name); } } 13 14 15 /// <summary> 16 /// 是否包含指定的配置元素 17 /// </summary> 18 /// <param name="name">配置元素名稱</param> 19 /// <returns>是否包含</returns> 20 public bool ContainsKey(string name) { return BaseGet(name) != null; } 21 22 /// <summary> 23 /// 添加元素 24 /// </summary> 25 /// <param name="obj"></param> 26 public virtual void Add(T obj) 27 { 28 BaseAdd(obj); 29 } 30 31 /// <summary> 32 /// 得到元素的Key值 33 /// </summary> 34 /// <param name="element">配置元素</param> 35 /// <returns>配置元素所對應的配置元素</returns> 36 protected override object GetElementKey(ConfigurationElement element) { return ((T)element).Name; } 37 38 /// <summary> 39 /// 生成新的配置元素實例 40 /// </summary> 41 /// <returns>配置元素實例</returns> 42 protected override ConfigurationElement CreateNewElement() { return new T(); } 43 }
定義基類後,ConnectionStrings、DataProviders、ConnectionDecrypts三個配置列表實體只需要繼承該基類,不需要任何實現。
1 public class ConnectionStringCollection: NamedConfigurationElementCollection<ConnectionStringElement> 2 { 3 4 5 6 } 7 8 public class DataProviderCollection: NamedConfigurationElementCollection<DataProviderElement> 9 { 10 11 } 12 13 public class ConnectionDecryptCollection: NamedConfigurationElementCollection<ConnectionDecryptElement> 14 { 15 16 17 }
通過以上配置實體類的定義,就可以使用以下方式獲取到資料庫配置信息:
DBConnectionConfiguration settings = DBConnectionConfiguration.GetConfig();
然後,根據資料庫連接的名稱獲取到對應的信息,比如:
var connectionString = settings.ConnectionStrings[dbName].ConnectionString;
這裡的DBName就是connectString配置項中的name信息。