[C#] .Net Core 全局配置讀取管理方法 ConfigurationManager

  最近在學習.Net Core的過程當中,發現.Net Framework中經常使用的ConfigurationManager在Core中居然被幹掉了。html

  也能理解。Core中使用的配置文件全是Json,不像Framework使用的XML,暫時不支持也是能理解的,可是畢竟全局配置文件這種東西還挺重要的,閱讀了一些文章後目前有3個解決方案。web

1、引入擴展System.Configuration.ConfigurationManager


  這個擴展庫能夠直接在Nuget中獲取。json

  使用方法和說明見 .NET Core 2.0遷移技巧之web.config配置文件緩存

  讀取的文件類型和方法都跟.Net Framework中一致,並且僅需引入包就能夠,瞬間很興奮有木有!app

  可是!在使用過過程當中發現這個擴展有問題。項目運行過程當中需修改個人app.config文件,對我項目中輸出的內容沒有絲毫影響,Debug發現獲取到的值的確沒有變化。重啓項目都沒有用。只有把項目從新編譯纔好使。ide

  不知道是否是由於個人打開方式不對,可是最終放棄這個方法。post

2、引入擴展Microsoft.Extensions.Options.ConfigurationExtensions

  這個擴展庫也能夠直接在Nuget中獲取。學習

  使用方法和說明見 ASP.NET Core實現類庫項目讀取配置文件url

  這個能夠讀取application.json中的配置參數,再也不使用XML能夠說很好的貼近Core的設計理念。spa

  惋惜,這個也有點美中不足的地方。首先跟上面的那個同樣,運行時修改json文件讀取到的內容不會改變,可是至少重啓項目能夠修改,這個讓我欣慰不少。另外就是,這個方法採用的是反序列化的原理,也就是必須有一個跟配置文件對應的實體類才能夠,這個感受比較雞肋,放棄。

3、自定義擴展方法

  這個是我此次說的重點,要是前面兩個方法能知足讀者你的需求,那麼就沒有必要看下去。

  廢話少說,先上代碼:

  1  public class ConfigurationManager
  2     {
  3         /// <summary>
  4         /// 配置內容
  5         /// </summary>
  6         private static NameValueCollection _configurationCollection = new NameValueCollection();
  7 
  8         /// <summary>
  9         /// 配置監聽響應鏈堆棧
 10         /// </summary>
 11         private static Stack<KeyValuePair<string, FileSystemWatcher>> FileListeners = new Stack<KeyValuePair<string, FileSystemWatcher>>();
 12 
 13         /// <summary>
 14         /// 默認路徑
 15         /// </summary>
 16         private static string _defaultPath = Directory.GetCurrentDirectory() + "\\appsettings.json";
 17 
 18         /// <summary>
 19         /// 最終配置文件路徑
 20         /// </summary>
 21         private static string _configPath = null;
 22 
 23         /// <summary>
 24         /// 配置節點關鍵字
 25         /// </summary>
 26         private static string _configSection = "AppSettings";
 27 
 28         /// <summary>
 29         /// 配置外鏈接的後綴
 30         /// </summary>
 31         private static string _configUrlPostfix = "Url";
 32 
 33         /// <summary>
 34         /// 最終修改時間戳
 35         /// </summary>
 36         private static long _timeStamp = 0L;
 37 
 38         /// <summary>
 39         /// 配置外鏈關鍵詞,例如:AppSettings.Url
 40         /// </summary>
 41         private static string _configUrlSection { get { return _configSection + "." + _configUrlPostfix; } }
 42 
 43 
 44         static ConfigurationManager()
 45         {
 46             ConfigFinder(_defaultPath);
 47         }
 48 
 49         /// <summary>
 50         /// 肯定配置文件路徑
 51         /// </summary>
 52         private static void ConfigFinder(string Path)
 53         {
 54             _configPath = Path;
 55             JObject config_json = new JObject();
 56             while (config_json != null)
 57             {
 58                 config_json = null;
 59                 FileInfo config_info = new FileInfo(_configPath);
 60                 if (!config_info.Exists) break;
 61 
 62                 FileListeners.Push(CreateListener(config_info));
 63                 config_json = LoadJsonFile(_configPath);
 64                 if (config_json[_configUrlSection] != null)
 65                     _configPath = config_json[_configUrlSection].ToString();
 66                 else break;
 67             }
 68 
 69             if (config_json == null || config_json[_configSection] == null) return;
 70 
 71             LoadConfiguration();
 72         }
 73 
 74         /// <summary>
 75         /// 讀取配置文件內容
 76         /// </summary>
 77         private static void LoadConfiguration()
 78         {
 79             FileInfo config = new FileInfo(_configPath);
 80             var configColltion = new NameValueCollection();
 81             JObject config_object = LoadJsonFile(_configPath);
 82             if (config_object == null || !(config_object is JObject)) return;
 83            
 84             if (config_object[_configSection]!=null)
 85             {
 86                 foreach (JProperty prop in config_object[_configSection])
 87                 {
 88                     configColltion[prop.Name] = prop.Value.ToString();
 89                 }
 90             }
 91             
 92             _configurationCollection = configColltion;
 93         }
 94 
 95         /// <summary>
 96         /// 解析Json文件
 97         /// </summary>
 98         /// <param name="FilePath">文件路徑</param>
 99         /// <returns></returns>
100         private static JObject LoadJsonFile(string FilePath)
101         {
102             JObject config_object = null;
103             try
104             {
105                 StreamReader sr = new StreamReader(FilePath, Encoding.Default);
106                 config_object = JObject.Parse(sr.ReadToEnd());
107                 sr.Close();
108             }
109             catch { }
110             return config_object;
111         }
112 
113         /// <summary>
114         /// 添加監聽樹節點
115         /// </summary>
116         /// <param name="info"></param>
117         /// <returns></returns>
118         private static KeyValuePair<string, FileSystemWatcher> CreateListener(FileInfo info)
119         {
120 
121             FileSystemWatcher watcher = new FileSystemWatcher();
122             watcher.BeginInit();
123             watcher.Path = info.DirectoryName;
124             watcher.Filter = info.Name;
125             watcher.IncludeSubdirectories = false;
126             watcher.EnableRaisingEvents = true;
127             watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Size;
128             watcher.Changed += new FileSystemEventHandler(ConfigChangeListener);
129             watcher.EndInit();
130 
131             return new KeyValuePair<string, FileSystemWatcher>(info.FullName, watcher);
132           
133         }
134 
135         private static void ConfigChangeListener(object sender, FileSystemEventArgs e)
136         {
137             long time = TimeStamp();
138             lock (FileListeners)
139             {
140                 if (time > _timeStamp)
141                 {
142                     _timeStamp = time;
143                     if (e.FullPath != _configPath || e.FullPath == _defaultPath)
144                     {
145                         while (FileListeners.Count > 0)
146                         {
147                             var listener = FileListeners.Pop();
148                             listener.Value.Dispose();
149                             if (listener.Key == e.FullPath) break;
150                         }
151                         ConfigFinder(e.FullPath);
152                     }
153                     else
154                     {
155                         LoadConfiguration();
156                     }
157                 }
158             }
159         }
160 
161         private static long TimeStamp()
162         {
163             return (long)((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds * 100);
164         }
165 
166         private static string c_configSection = null;
167         public static string ConfigSection
168         {
169             get { return _configSection; }
170             set { c_configSection = value; }
171         }
172 
173 
174         private static string c_configUrlPostfix = null;
175         public static string ConfigUrlPostfix
176         {
177             get { return _configUrlPostfix; }
178             set { c_configUrlPostfix = value; }
179         }
180 
181         private static string c_defaultPath = null;
182         public static string DefaultPath
183         {
184             get { return _defaultPath; }
185             set { c_defaultPath = value; }
186         }
187 
188         public static NameValueCollection AppSettings
189         {
190             get { return _configurationCollection; }
191         }
192 
193         /// <summary>
194         /// 手動刷新配置,修改配置後,請手動調用此方法,以便更新配置參數
195         /// </summary>
196         public static void RefreshConfiguration()
197         {
198             lock (FileListeners)
199             {
200                 //修改配置
201                 if (c_configSection != null) { _configSection = c_configSection; c_configSection = null; }
202                 if (c_configUrlPostfix != null) { _configUrlPostfix = c_configUrlPostfix; c_configUrlPostfix = null; }
203                 if (c_defaultPath != null) { _defaultPath = c_defaultPath; c_defaultPath = null; }
204                 //釋放掉所有監聽響應鏈
205                 while (FileListeners.Count > 0)
206                     FileListeners.Pop().Value.Dispose();
207                 ConfigFinder(_defaultPath);
208             }
209         }
210 
211     }

 

  最開始設計的是採用緩存,每次調用比對文件的修改時間,大小等特徵,出現變化重新載入配置。後來發現圖樣圖森破!

  C#提供了專門監聽文件系統的方法。因此重新設計了監聽響應鏈堆棧來實現。

  

  使用說明:

    一、配置節點:

      能夠直接寫在項目默認的配置文件appsettings.json中 格式以下

{
  "AppSettings": {
    "Title": "Test",
    "Version": "1.2.1",
    "AccessToken": "123456@abc.com"
  }
}
View Code

      保證配置節點AppSettings存在,剩下的就是以Key-Value的形式來寫屬性,就能夠。

    二、外部配置文件

      像.Net Framework中同樣,能夠經過外部配置文件來實現。格式以下

1 {
2   "AppSettings.Url": "D:\\test\\app1.json"
3 }
View Code

      採用格式是「配置節點名.外鏈後綴」的形式。能夠設計多級外部配置文件,只要發現有外部配置節點就會向下尋找,並監聽鏈上的全部節點文件的變化。

      可是須要注意的是:一旦存在外部配置節點,此文件中的配置節點和參數將再也不參與解析

    三、可配置初始化參數

      包括默認文件路徑在內的多個參數都可以修改,詳情見代碼。

      修改後須要手動調用RefreshConfiguration方法,以使配置內容生效,有點像事務處理。建議在項目的Startup方法中修改配置方法。

    四、使用

      跟.Net Framework中同樣,直接調用ConfigurationManager.Appsettings["Title"]就能夠了。

 

以上代碼功能徹底原創,轉載請著名出處。若是有任何問題和疑問歡迎提出,能夠給我郵件或者直接留言。

相關文章
相關標籤/搜索