最近在学习.Net Core的过程中,发现.Net Framework中常用的ConfigurationManager在Core中竟然被干掉了。
也能理解。Core中使用的配置文件全是Json,不像Framework使用的XML,暂时不支持也是能理解的,但是毕竟全局配置文件这种东西还挺重要的,阅读了一些文章后目前有3个解决方案。
一、引入扩展System.Configuration.ConfigurationManager
这个扩展库可以直接在Nuget中获取。
使用方法和说明见.NET Core 2.0迁移技巧之web.config配置文件
读取的文件类型和方法都跟.Net Framework中一致,而且仅需引入包就可以,瞬间很兴奋有木有!
但是!在使用过过程中发现这个扩展有问题。项目运行过程中需修改我的app.config文件,对我项目中输出的内容没有丝毫影响,Debug发现获取到的值的确没有变化。重启项目都没有用。只有把项目重新编译才好使。
不知道是不是因为我的打开方式不对,但是最终放弃这个方法。
二、引入扩展Microsoft.Extensions.Options.ConfigurationExtensions
这个扩展库也可以直接在Nuget中获取。
使用方法和说明见 ASP.NET Core实现类库项目读取配置文件
这个可以读取application.json中的配置参数,不再使用XML可以说很好的贴近Core的设计理念。
可惜,这个也有点美中不足的地方。首先跟上面的那个一样,运行时修改json文件读取到的内容不会改变,但是至少重启项目可以修改,这个让我欣慰很多。另外就是,这个方法采用的是反序列化的原理,也就是必须有一个跟配置文件对应的实体类才可以,这个感觉比较鸡肋,放弃。
三、自定义扩展方法
这个是我这次说的重点,要是前面两个方法能满足读者你的需求,那么就没有必要看下去。
废话少说,先上代码:
public class ConfigurationManager { /// <summary> /// 配置内容 /// </summary> private static NameValueCollection _configurationCollection = new NameValueCollection(); /// <summary> /// 配置监听响应链堆栈 /// </summary> private static Stack<KeyValuePair<string, FileSystemWatcher FileListeners = new Stack<KeyValuePair<string, FileSystemWatcher(); /// <summary> /// 默认路径 /// </summary> private static string _defaultPath = Directory.GetCurrentDirectory() + "\\appsettings.json"; /// <summary> /// 最终配置文件路径 /// </summary> private static string _configPath = null; /// <summary> /// 配置节点关键字 /// </summary> private static string _configSection = "AppSettings"; /// <summary> /// 配置外连接的后缀 /// </summary> private static string _configUrlPostfix = "Url"; /// <summary> /// 最终修改时间戳 /// </summary> private static long _timeStamp = 0L; /// <summary> /// 配置外链关键词,例如:AppSettings.Url /// </summary> private static string _configUrlSection { get { return _configSection + "." + _configUrlPostfix; } } static ConfigurationManager() { ConfigFinder(_defaultPath); } /// <summary> /// 确定配置文件路径 /// </summary> private static void ConfigFinder(string Path) { _configPath = Path; JObject config_json = new JObject(); while (config_json != null) { config_json = null; FileInfo config_info = new FileInfo(_configPath); if (!config_info.Exists) break; FileListeners.Push(CreateListener(config_info)); config_json = LoadJsonFile(_configPath); if (config_json[_configUrlSection] != null) _configPath = config_json[_configUrlSection].ToString(); else break; } if (config_json == null || config_json[_configSection] == null) return; LoadConfiguration(); } /// <summary> /// 读取配置文件内容 /// </summary> private static void LoadConfiguration() { FileInfo config = new FileInfo(_configPath); var configColltion = new NameValueCollection(); JObject config_object = LoadJsonFile(_configPath); if (config_object == null || !(config_object is JObject)) return; if (config_object[_configSection]!=null) { foreach (JProperty prop in config_object[_configSection]) { configColltion[prop.Name] = prop.Value.ToString(); } } _configurationCollection = configColltion; } /// <summary> /// 解析Json文件 /// </summary> /// <param name="FilePath">文件路径</param> /// <returns></returns> private static JObject LoadJsonFile(string FilePath) { JObject config_object = null; try { StreamReader sr = new StreamReader(FilePath, Encoding.Default); config_object = JObject.Parse(sr.ReadToEnd()); sr.Close(); } catch { } return config_object; } /// <summary> /// 添加监听树节点 /// </summary> /// <param name="info"></param> /// <returns></returns> private static KeyValuePair<string, FileSystemWatcher> CreateListener(FileInfo info) { FileSystemWatcher watcher = new FileSystemWatcher(); watcher.BeginInit(); watcher.Path = info.DirectoryName; watcher.Filter = info.Name; watcher.IncludeSubdirectories = false; watcher.EnableRaisingEvents = true; watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Size; watcher.Changed += new FileSystemEventHandler(ConfigChangeListener); watcher.EndInit(); return new KeyValuePair<string, FileSystemWatcher>(info.FullName, watcher); } private static void ConfigChangeListener(object sender, FileSystemEventArgs e) { long time = TimeStamp(); lock (FileListeners) { if (time > _timeStamp) { _timeStamp = time; if (e.FullPath != _configPath || e.FullPath == _defaultPath) { while (FileListeners.Count > 0) { var listener = FileListeners.Pop(); listener.Value.Dispose(); if (listener.Key == e.FullPath) break; } ConfigFinder(e.FullPath); } else { LoadConfiguration(); } } } } private static long TimeStamp() { return (long)((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds * 100); } private static string c_configSection = null; public static string ConfigSection { get { return _configSection; } set { c_configSection = value; } } private static string c_configUrlPostfix = null; public static string ConfigUrlPostfix { get { return _configUrlPostfix; } set { c_configUrlPostfix = value; } } private static string c_defaultPath = null; public static string DefaultPath { get { return _defaultPath; } set { c_defaultPath = value; } } public static NameValueCollection AppSettings { get { return _configurationCollection; } } /// <summary> /// 手动刷新配置,修改配置后,请手动调用此方法,以便更新配置参数 /// </summary> public static void RefreshConfiguration() { lock (FileListeners) { //修改配置 if (c_configSection != null) { _configSection = c_configSection; c_configSection = null; } if (c_configUrlPostfix != null) { _configUrlPostfix = c_configUrlPostfix; c_configUrlPostfix = null; } if (c_defaultPath != null) { _defaultPath = c_defaultPath; c_defaultPath = null; } //释放掉全部监听响应链 while (FileListeners.Count > 0) FileListeners.Pop().Value.Dispose(); ConfigFinder(_defaultPath); } } }
最开始设计的是采用缓存,每次调用比对文件的修改时间,大小等特征,出现变化从新载入配置。后来发现图样图森破!
C#提供了专门监听文件系统的方法。所以从新设计了监听响应链堆栈来实现。
使用说明:
1、配置节点:
可以直接写在项目默认的配置文件appsettings.json中 格式如下
{ "AppSettings": { "Title": "Test", "Version": "1.2.1", "AccessToken": "123456@abc.com" } }
保证配置节点AppSettings存在,剩下的就是以Key-Value的形式来写属性,就可以。
2、外部配置文件
像.Net Framework中一样,可以通过外部配置文件来实现。格式如下
{ "AppSettings.Url": "D:\\test\\app1.json" }
采用格式是“配置节点名.外链后缀”的形式。可以设计多级外部配置文件,只要发现有外部配置节点就会向下寻找,并监听链上的所有节点文件的变化。
但是需要注意的是:一旦存在外部配置节点,此文件中的配置节点和参数将不再参与解析
3、可配置初始化参数
包括默认文件路径在内的多个参数均可以修改,详情见代码。
修改后需要手动调用RefreshConfiguration方法,以使配置内容生效,有点像事务处理。建议在项目的Startup方法中修改配置方法。
4、使用
跟.Net Framework中一样,直接调用ConfigurationManager.Appsettings["Title"]就可以了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]