在應用程式的開發過程中,我們往往會為軟體提供一些配置項,以允許軟體根據配置項靈活來做事情,比如配置日誌文件路徑等,此外,我們還可以用配置項來為用戶存儲其偏好設置等。 .NET 為我們預設提供了配置機制以及配置文件,項目中的 app.config 或者 web.config 文件(如果沒有,可以添加) ...
在應用程式的開發過程中,我們往往會為軟體提供一些配置項,以允許軟體根據配置項靈活來做事情,比如配置日誌文件路徑等,此外,我們還可以用配置項來為用戶存儲其偏好設置等。
.NET 為我們預設提供了配置機制以及配置文件,項目中的 app.config 或者 web.config 文件(如果沒有,可以添加)就是 .NET 為我們提供的配置文件。在這個配置文件中的根節點 configuration 下,創建 appSettings 節點,在此節點中,我們可以添加自定義的配置項。同時,ConfigurationManager 類提供了訪問及操作此配置文件(由 Configuration 類代表)中配置的方法。需要註意的是,這個類在 System.Configuration.dll 文件中,需要將它添加到項目的引用中,才能使用。
本文主要介紹一種更為便利的方式來訪問/存儲配置項,當然,它本質上是使用 ConfigurationManager 類完成的。它主要的特點是以面向對象的方式來解決此問題,更具體地說,我們創建一個類,類中包括一些屬性用以表示配置項,通過訪問或設置這些屬性,即可得到或更新對應的配置項。
一、實現
首先,我們為 Configuration 類添加一個擴展方法 AddOrUpdateAppSettingItem,如下 :
/// <summary> /// 向配置的 AppSetings 節添加(如果不存在)或更新(如果已存在)給定的 key 和 value /// </summary> /// <param name="config"></param> /// <param name="key"></param> /// <param name="value"></param> public static void AddOrUpdateAppSettingItem(this Configuration config, string key, string value) { if (config.AppSettings.Settings.AllKeys.Contains(key)) { config.AppSettings.Settings[key].Value = value; } else { config.AppSettings.Settings.Add(key, value); } } }
這個方法主要實現了向 appSettings 節點添加(配置項不存在)或更新(配置項已存在)配置,接下來我們會用到這個方法。
接著,我們定義抽象基類 ConfigSetting,如下:
public abstract class ConfigSetting { /// <summary> /// 配置類 /// </summary> /// <param name="configuration">配置</param> public ConfigSetting(Configuration configuration) { Configuration = configuration; } /// <summary> /// 當前配置 /// </summary> public Configuration Configuration { get; } /// <summary> /// 獲取當前程式配置 /// </summary> /// <param name="config"></param> /// <returns></returns> public static Configuration GetCurrentConfiguration() { return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); } /// <summary> /// 返回指定的配置項的值 /// </summary> /// <param name="settingKey"></param> /// <returns></returns> protected virtual string GetSettingValue([CallerMemberName] string settingKey = null) { return Configuration?.AppSettings?.Settings[settingKey]?.Value; } /// <summary> /// 返回指定的配置項的值 /// </summary> /// <typeparam name="T">值類型</typeparam> /// <param name="settingKey"></param> /// <returns></returns> protected virtual T GetSettingValue<T>([CallerMemberName] string settingKey = null) { var value = GetSettingValue(settingKey); if (string.IsNullOrWhiteSpace(value)) { return default(T); } else { return (T)Convert.ChangeType(value, typeof(T)); } } /// <summary> /// 為指定的配置項設置值 /// </summary> /// <param name="value"></param> /// <param name="settingKey"></param> protected virtual void SetSettingValue(object value, [CallerMemberName] string settingKey = null) { Configuration.AddOrUpdateAppSettingItem(settingKey, value?.ToString()); Configuration.Save(); } }
其中主要包括了一個靜態方法和三個受保護的 virtual 方法,說明:
1. 靜態方法 GetCurrentConfiguration 返回當前應用的配置類;
2. GetSettingValue 和 SetSettingValue 方法則分別負責讀取、設置指定配置項的值;
3. GetSettingValue 有兩個重載,其中一個用於支持泛型;
4. 在它們的方法簽名中包括 CallerMemberName 特性,通過這個屬性可以得到調用此訪問的方法或屬性的名稱。
然後,創建一個名為 AppConfigSetting 的類,這個類將會包括一些代表配置項的屬性,並且它要繼承自 ConfigSetting,如下:
public class AppConfigSetting : ConfigSetting { public AppConfigSetting(Configuration configuration) : base(configuration) { } public DateTime InstallDateTime { get { return GetSettingValue<DateTime>(); } set { SetSettingValue(value); } } public string LogFileName { get { return GetSettingValue(); } set { SetSettingValue(value); } } public int ReadBlockSize { get { return GetSettingValue<int>(); } set { SetSettingValue(value); } } }
說明:
1. 可以看到我們在其中增加了三個屬性。而在它們的 get 與 set 段中,調用了基類中的對應的兩個方法,其中,對於非 string 類型的配置項,我們調用的是 GetSettingValue<T>。
2. 通過我們前面提到的 CallerMemberName 特性,就可以得到這裡的屬性名,並得到相應的配置項,這樣我們就無需硬編碼。所以,這個屬性名,本質上就是配置項的名稱。
這樣,我們將所有要用到的配置項作為屬性放到 AppConfigSetting 類中,再用操作這些屬性就可以完成所有對配置項的操作了。
二、如何使用
使用它,也非常簡單,代碼如下:
var config = ConfigSetting.GetCurrentConfiguration(); AppConfigSetting setting = new AppConfigSetting(config); // 未設置時 MessageBox.Show($"LogFileName: {setting.LogFileName}"); // 設置後,再讀取 setting.LogFileName = "log.txt"; MessageBox.Show($"LogFileName: {setting.LogFileName}");
三、補充
為了滿足在不向 AppConfigSetting 添加配置項屬性,但卻又要訪問/存儲指定配置項的需要,我們可以在基類 ConfigSetting 中添加以下三個方法:
/// <summary> /// 返回指定的配置項的值 /// </summary> /// <param name="settingKey"></param> /// <returns></returns> public string GetSettingValueByKey(string settingKey) { return GetSettingValue(settingKey); } /// <summary> /// 返回指定的配置項的值 /// </summary> /// <param name="settingKey"></param> /// <returns></returns> public T GetSettingValueByKey<T>(string settingKey) { return GetSettingValue<T>(settingKey); } /// <summary> /// 為指定的配置項設置值 /// </summary> /// <param name="value"></param> /// <param name="settingKey"></param> public void SetSettingValueByKey(string settingKey, object value) { SetSettingValue(value, settingKey); }
使用這幾個方法,可以自由地訪問/存儲配置項,不同於上面增加屬性方式的是,它需要自己傳遞配置項 key 作參數。
使用:
// 未設置時 MessageBox.Show($"LogLevel: {setting.GetSettingValueByKey("LogLevel")}"); // 設置後,再讀取 setting.SetSettingValueByKey("LogLevel", 5); MessageBox.Show($"LogLevel: {setting.GetSettingValueByKey("LogLevel")}");
總結
本文主要介紹了一種訪問應用程式配置更為便利的方式,其主要思想是通過基類中 GetSettingValue/SetSettingValue 兩個方法藉助於 CallerMemberName 特性而得到派生類中屬性的名稱而操作對應的配置項。當然,這裡不僅提供了一種方法,更是提供一種思路,基於此,你還可以根據實際需要來調整、擴展以滿足你的實際需要。