[C#] .Net Core 全局配置读取管理方法 ConfigurationManager
最近在学习.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 > )
{
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(, , , , , , DateTimeKind.Utc)).TotalMilliseconds * );
} 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 > )
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"]就可以了。
以上代码功能完全原创,转载请著名出处。如果有任何问题和疑问欢迎提出,可以给我邮件或者直接留言。
[C#] .Net Core 全局配置读取管理方法 ConfigurationManager的更多相关文章
- MFC 全局配置 读取保存配置
不知道关于全局配置别人都是怎么处理的,最近做的东西都用到全局配置,而且要保存软件的设置,下次启动时要使用上次关闭时的配置. 我的做法是建一个类用来保存和读取配置,并且在这个类中创建一些变量,供所有的界 ...
- Mybatis --- 创建方法、全局配置
总体介绍:MyBatis实际上是Ibatis3.0版本以后的持久化层框架[也就是和数据库打交道的框架]! 和数据库打交道的技术有: 原生的JDBC技术--->Spring的Jd ...
- .Net Core 自定义配置源从配置中心读取配置
配置,几乎所有的应用程序都离不开它..Net Framework时代我们使用App.config.Web.config,到了.Net Core的时代我们使用appsettings.json,这些我们再 ...
- .NET Core技术研究-配置读取
升级ASP.NET Core后,配置的读取是第一个要明确的技术.原先的App.Config.Web.Config.自定义Config在ASP.NET Core中如何正常使用.有必要好好总结整理一下,相 ...
- ASP.NET Core的配置(1):读取配置信息
提到"配置"二字,我想绝大部分.NET开发人员脑海中会立马浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化 ...
- thinkphp中的配置与读取C方法详解
1.项目公共配置 Conf/config.php 内容如下 <?php /** *项目公共配置 *@package *@author **/ return array( 'LOAD_EXT_CO ...
- asp.net core 3.0 MVC JSON 全局配置
asp.net core 3.0 MVC JSON 全局配置 System.Text.Json(default) startup配置代码如下: using System.Text.Encodings. ...
- iview Message(全局提示)与Notice(通知提醒)全局配置方法
在使用iview 的Message与Notice组件时,可以对提示框的显示位置与显示时长进行配置. iview提供了两个配置属性.分别是: top 提示组件距离顶端的距离,单位像素. duration ...
- nginx全局配置和性能优化
nginx目录结构和命令 1.ls /apps/nginx/: html是测试页,sbin是主程序 2.ls /apps/nginx/sbin/: nginx 只有一个程序文件 3. ...
随机推荐
- C++ STL 栈和队列详解
一.解释: 1.栈 栈是一种特殊的线性表.其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行.如下所示: 结论:后进先出(Last In First Out),简称为LIFO线性表. 举个 ...
- 分布式事务,EventBus 解决方案:CAP【中文文档】
前言 很多同学想对CAP的机制以及用法等想有一个详细的了解,所以花了将近两周时间写了这份中文的CAP文档,对 CAP 还不知道的同学可以先看一下这篇文章. 本文档为 CAP 文献(Wiki),本文献同 ...
- easyui项目问题集锦
1.级联问题(combobox) combobox至多可以保存2个东西value和text,但我需要第三个数的时候,怎么办?比如,省.市.区的三级级联,我选择市的时候,需要市id,市name,区号,邮 ...
- Numpy 操作
一.Numpy 属性 # 列表转化为矩阵 In []: arr = np.array([[,,],[,,]]) In []: arr Out[]: array([[, , ], [, , ]]) 1, ...
- 写一个Vue loading 插件
什么是vue插件? 从功能上说,插件是为Vue添加全局功能的一种机制,比如给Vue添加一个全局组件,全局指令等: 从代码结构上说,插件就是一个必须拥有install方法的对象,这个方法的接收的第一个参 ...
- shell脚本报错:"[: =: unary operator expected"
shell脚本报错:"[: =: unary operator expected" 在匹配字符串相等时,我用了类似这样的语句: if [ $STATUS == "OK&q ...
- python之----------字符编码具体原理
1.内存和硬盘都是用来存储的. CPU:速度快 硬盘:永久保存 2.文本编辑器存取文件的原理(nodepad++,pycharm,word) 打开编辑器就可以启动一个进程,是在内存中的,所以在编辑器编 ...
- HTML-CSS相关(1)
一 浮动 1.标准流中的块级盒子,宽度将会自动伸展为100%而浮动的块级盒子,宽度不会自动伸展,而是由内容撑开. 2.当一个盒子浮动,标准流中未浮动的其他盒子,将视浮动盒子不存在而占据浮动盒子原来的 ...
- noip普及组2007 奖学金
奖学金 描述 某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金.期末,每个学生都有3门课的成绩:语文.数学.英语.先按总分从高到低排序,如果两个同学总分相同,再按语文成绩 ...
- 理解angularJs中的$on,$broadcast,$emit
$emit作用是将一个事件从子作用域广播至父作用域,直至根作用域.(包括自己) $emit有两个参数name和args,name就是需要广播的名字,args是一个或者多个参数. $broadcast的 ...