C# 程序修改config文件后,不重启程序刷新配置ConfigurationManager
基本共识:
ConfigurationManager 自带缓存,且不支持 写入。
如果 通过 文本写入方式 修改 配置文件,程序 无法刷新加载 最新配置。
PS. Web.config 除外:Web.config 修改后,网站会重启 (即 Web 程序 也无法在 运行时 刷新配置)。
为什么要在程序运行时,修改配置(刷新配置):
> 以前C++,VB 时代,用户在程序界面 勾选的配置,会写到 ini 文件。
> C# 自带 .exe.config 配置文件 —— 但是,C# 自带的 ConfigurationManager 不支持 运行时 修改,运行时刷新配置。
> 本文 提供工具类,彻底 解决 这个问题 —— 从此,用户手动勾选的配置 再也不用写入 ini,而是直接修改 .exe.config 文件,且立即刷新。
刷新 ConfigurationManager 配置 的 代码 有两种:
> 第一种:
ConfigurationManager.RefreshSection("appSettings"); //刷新 appSettings 节点 (立即生效)
ConfigurationManager.RefreshSection("connectionString"); //刷新 connectionString 节点 (无法生效 —— 可能是 微软处理时,因为 LocalSqlServer 这个默认配置 而导致的疏忽)
> 第二种:
FieldInfo fieldInfo = typeof(ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic | BindingFlags.Static);
if (fieldInfo != null) fieldInfo.SetValue(null, ); //将配置文件 设置为: 未分析 状态, 配置文件 将会在下次读取 时 重新分析.
//立即生效,而且效果 明显 —— 就喜欢这种 暴力做法。
一起反编译 ConfigurationManager 代码:
> 首先 下载 ILSpy 或 Reflector (本文使用的是 ILSpy.)
> 打开 ILSpy 搜索 ConfigurationManager,执行如下操作:
> 编写 反射代码,刷新 配置文件数据。(具体代码 在 文章最开始。)
额外提供 配置文件 修改的 工具类代码:
以下代码 实现如下功能:
> 执行 配置写入操作时,自动创建 .exe.config 文件,自动创建 appSettings connectionString 节点。
> .exe.config 写入配置时,如果 相同的 key name 存在,则修改,不存在 则创建。
> 额外的 审美操作:
> 很多人习惯 appSettings 显示在 connectionString 前面。
> 很多人习惯 appSettings 在 最前面。
> appSettings 必须在 configSections 后面。(configSections 配置文件 扩展配置节点,只能写在第一个,否则 程序报错。)
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Xml; namespace InkFx.Utils
{
public partial class Tools
{ private static ConfigAppSetting m_AppSettings;
private static ConfigConnectionStrings m_ConnectionStrings; public static ConfigAppSetting AppSettings
{
get
{
if (m_AppSettings == null)
{
m_AppSettings = new ConfigAppSetting();
m_AppSettings.AppSettingChanged += OnAppSettingChanged;
}
return m_AppSettings;
}
}
public static ConfigConnectionStrings ConnectionStrings
{
get
{
if (m_ConnectionStrings == null)
{
m_ConnectionStrings = new ConfigConnectionStrings();
m_ConnectionStrings.ConnectionStringsChanged += OnConnectionStringsChanged;
}
return m_ConnectionStrings;
}
} private static void OnAppSettingChanged(string name, string value)
{
string configPath = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
if (!File.Exists(configPath))
{
const string content = @"<?xml version=""1.0""?><configuration></configuration>";
File.WriteAllText(configPath, content, Encoding.UTF8);
} XmlDocument doc = new XmlDocument();
doc.Load(configPath); XmlNode nodeConfiguration = doc.SelectSingleNode(@"configuration");
if (nodeConfiguration == null)
{
nodeConfiguration = doc.CreateNode(XmlNodeType.Element, "configuration", string.Empty);
doc.AppendChild(nodeConfiguration);
} XmlNode nodeAppSettings = nodeConfiguration.SelectSingleNode(@"appSettings");
if (nodeAppSettings == null)
{
nodeAppSettings = doc.CreateNode(XmlNodeType.Element, "appSettings", string.Empty);
if (!nodeConfiguration.HasChildNodes)
nodeConfiguration.AppendChild(nodeAppSettings);
else
{
//configSections 必须放在 第一个, 所以得 避开 configSections
XmlNode firstNode = nodeConfiguration.ChildNodes[];
bool firstNodeIsSections = string.Equals(firstNode.Name, "configSections", StringComparison.CurrentCultureIgnoreCase); if (firstNodeIsSections)
nodeConfiguration.InsertAfter(nodeAppSettings, firstNode);
else
nodeConfiguration.InsertBefore(nodeAppSettings, firstNode);
}
} string xmlName = FormatXmlStr(name);
XmlNode nodeAdd = nodeAppSettings.SelectSingleNode(@"add[@key='" + xmlName + "']");
if (nodeAdd == null)
{
nodeAdd = doc.CreateNode(XmlNodeType.Element, "add", string.Empty);
nodeAppSettings.AppendChild(nodeAdd);
} XmlElement nodeElem = (XmlElement)nodeAdd;
nodeElem.SetAttribute("key", name);
nodeElem.SetAttribute("value", value);
doc.Save(configPath); try { ConfigurationManager.RefreshSection("appSettings"); } catch (Exception) { }
}
private static void OnConnectionStringsChanged(string name, string value)
{
string configPath = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
if (!File.Exists(configPath))
{
const string content = @"<?xml version=""1.0""?><configuration></configuration>";
File.WriteAllText(configPath, content, Encoding.UTF8);
} XmlDocument doc = new XmlDocument();
doc.Load(configPath); XmlNode nodeConfiguration = doc.SelectSingleNode(@"configuration");
if (nodeConfiguration == null)
{
nodeConfiguration = doc.CreateNode(XmlNodeType.Element, "configuration", string.Empty);
doc.AppendChild(nodeConfiguration);
} XmlNode nodeAppSettings = nodeConfiguration.SelectSingleNode(@"appSettings");
XmlNode nodeConnectionStrings = nodeConfiguration.SelectSingleNode(@"connectionStrings");
if (nodeConnectionStrings == null)
{
nodeConnectionStrings = doc.CreateNode(XmlNodeType.Element, "connectionStrings", string.Empty);
if (!nodeConfiguration.HasChildNodes)
nodeConfiguration.AppendChild(nodeConnectionStrings);
else
{
//优先将 connectionStrings 放在 appSettings 后面
if (nodeAppSettings != null)
nodeConfiguration.InsertAfter(nodeConnectionStrings, nodeAppSettings);
else
{
//如果 没有 appSettings 节点, 则 configSections 必须放在 第一个, 所以得 避开 configSections
XmlNode firstNode = nodeConfiguration.ChildNodes[];
bool firstNodeIsSections = string.Equals(firstNode.Name, "configSections", StringComparison.CurrentCultureIgnoreCase); if (firstNodeIsSections)
nodeConfiguration.InsertAfter(nodeConnectionStrings, firstNode);
else
nodeConfiguration.InsertBefore(nodeConnectionStrings, firstNode);
}
}
} string xmlName = FormatXmlStr(name);
XmlNode nodeAdd = nodeConnectionStrings.SelectSingleNode(@"add[@name='" + xmlName + "']");
if (nodeAdd == null)
{
nodeAdd = doc.CreateNode(XmlNodeType.Element, "add", string.Empty);
nodeConnectionStrings.AppendChild(nodeAdd);
} XmlElement nodeElem = (XmlElement)nodeAdd;
nodeElem.SetAttribute("name", name);
nodeElem.SetAttribute("connectionString", value);
doc.Save(configPath); try
{
ConfigurationManager.RefreshSection("connectionString"); //RefreshSection 无法刷新 connectionString 节点
FieldInfo fieldInfo = typeof(ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic | BindingFlags.Static);
if (fieldInfo != null) fieldInfo.SetValue(null, ); //将配置文件 设置为: 未分析 状态, 配置文件 将会在下次读取 时 重新分析.
}
catch (Exception) { }
} private static string FormatXmlStr(string value)
{
if (string.IsNullOrEmpty(value)) return string.Empty; string result = value
.Replace("<", "<")
.Replace(">", ">")
.Replace("&", "&")
.Replace("'", "'")
.Replace("\"", """);
return result;
//< < 小于号
//> > 大于号
//& & 和
//' ' 单引号
//" " 双引号
} public class ConfigAppSetting
{
private readonly InnerIgnoreDict<string> m_Hash = new InnerIgnoreDict<string>(); public string this[string name]
{
get
{
string value = m_Hash[name];
if (string.IsNullOrWhiteSpace(value))
{
try { value = ConfigurationManager.AppSettings[name]; } catch(Exception) { }
m_Hash[name] = value;
return value;
}
return value;
}
set
{
m_Hash[name] = value;
try{ ConfigurationManager.AppSettings[name] = value; } catch(Exception) { }
if (AppSettingChanged != null) AppSettingChanged(name, value);
}
}
public AppSettingValueChanged AppSettingChanged; public delegate void AppSettingValueChanged(string name, string value);
}
public class ConfigConnectionStrings
{
private readonly InnerIgnoreDict<ConnectionStringSettings> m_Hash = new InnerIgnoreDict<ConnectionStringSettings>(); public string this[string name]
{
get
{
ConnectionStringSettings value = m_Hash[name];
if (value == null || string.IsNullOrWhiteSpace(value.ConnectionString))
{
try { value = ConfigurationManager.ConnectionStrings[name]; } catch (Exception) { }
m_Hash[name] = value;
return value == null ? string.Empty : value.ConnectionString;
}
return value.ConnectionString;
}
set
{ ConnectionStringSettings setting = new ConnectionStringSettings();
setting.Name = name;
setting.ConnectionString = value;
m_Hash[name] = setting;
//try { ConfigurationManager.ConnectionStrings[name] = setting; } catch (Exception) { }
if (ConnectionStringsChanged != null) ConnectionStringsChanged(name, value);
}
}
public ConnectionStringsValueChanged ConnectionStringsChanged; public delegate void ConnectionStringsValueChanged(string name, string value);
} private class InnerIgnoreDict<T> : Dictionary<string, T>
{
public InnerIgnoreDict(): base(StringComparer.CurrentCultureIgnoreCase)
{
} #if (!WindowsCE && !PocketPC)
public InnerIgnoreDict(SerializationInfo info, StreamingContext context) : base(info, context) { }
#endif private readonly object getSetLocker = new object();
private static readonly T defaultValue = default(T); public new T this[string key]
{
get
{
if (key == null) return defaultValue;
lock (getSetLocker) //为了 多线程的 高并发, 取值也 加上 线程锁
{
T record;
if (TryGetValue(key, out record)) return record;
else return defaultValue;
}
}
set
{
try
{
if (key != null)
{
lock (getSetLocker)
{
//if (!value.Equals(default(T)))
//{
if (base.ContainsKey(key)) base[key] = value;
else base.Add(key, value);
//}
//else
//{
// base.Remove(key);
//}
}
}
}
catch (Exception) { }
}
}
} }
}
工具类使用代码:

static void Main(string[] args)
{
Tools.AppSettings["Test"] = "Love"; //修改配置文件
Console.WriteLine(ConfigurationManager.AppSettings["Test"]); //传统方式 读取配置文件
Console.WriteLine(Tools.AppSettings["Test"]); //工具类 读取配置文件 Tools.ConnectionStrings["ConnString"] = "Data Source=127.0.0.1;Initial Catalog=master;User=sa;password=123.com;";
Console.WriteLine(ConfigurationManager.ConnectionStrings["ConnString"]);
Console.WriteLine(Tools.ConnectionStrings["ConnString"]); Tools.AppSettings["Test"] = "<Love>";
Console.WriteLine(ConfigurationManager.AppSettings["Test"]);
Console.WriteLine(Tools.AppSettings["Test"]); Console.ReadKey();
}

执行结果:
配置文件变化:
> 程序执行前,删除配置文件。
> 程序执行后,自动生成配置文件。
出处:https://www.cnblogs.com/shuxiaolong/p/20160907_1432.html
C# 程序修改config文件后,不重启程序刷新配置ConfigurationManager的更多相关文章
- Config文件的使用:通过程序修改Config文件
对于config文件,一般情况下都是使用ConfigurationManager加载,然后通过读取相应节点的值来获取想要的数据,但是,有时候需要修改config文件的值,这时候就用到了OpenExeC ...
- [VS2008] Debug版本程序发布后 由于应用程序的配置不正确,应用程序未能启动,重新安装应用程序可能会纠正这个问题
转自VC错误:http://www.vcerror.com/?p=59 问题描述: [VS2008] 版本程序发布后,运行程序弹出错误框: 由于应用程序的配置不正确,应用程序未能启动,重新安装应用程序 ...
- webstorm设置修改文件后自动编译并刷新浏览器页面
转载:http://www.cnblogs.com/ssrsblogs/p/6155747.html 重装了 webstorm ,从10升级到了2016 一升不要紧,打开老项目,开启webpakc-d ...
- WPF程序中App.Config文件的读与写
WPF程序中的App.Config文件是我们应用程序中经常使用的一种配置文件,System.Configuration.dll文件中提供了大量的读写的配置,所以它是一种高效的程序配置方式,那么今天我就 ...
- WinForm读取指定的config文件的内容
config文件的使用 一.缘起 最近做项目开始使用C#,因为以前一直使用的是C++,因此面向对象思想方面的知识还是比较全面的,反而是因没有经过完整.系统的.Net方面知识的系统学习,经常被一些在C# ...
- 浅谈config文件的使用
一.缘起 最近做项目开始使用C#,因为以前一直使用的是C++,因此面向对象思想方面的知识还是比较全面的,反而是因没有经过完整.系统的.Net方面知识的系统学习,经常被一些在C#老鸟眼里几乎是常识的小知 ...
- ASP.Net Web.config 中引用外部config文件
1. 前提准备: Web.config file: <?xml version="1.0" encoding="utf-8"?><config ...
- 微软ASP.NET网站部署指南(3):使用Web.Config文件的Transformations
1. 综述 大多数程序里都会在Web.config里设置參数,而且在部署的时候须要更改. 每次都手工更改这些配置非常乏味,也easy出错. 该章节将会告诉你假设通过自己主动化更新Web.config文 ...
- 配置文件——App.config文件读取和修改
作为普通的xml文件读取的话,首先就要知道怎么寻找文件的路径.我们知道一般配置文件就在跟可执行exe文件在同一目录下,且仅仅在名称后面添加了一个.config 因此,可以用Application.Ex ...
随机推荐
- Java虚拟机学习-Java内存区域(一)
Java虚拟机内存划分为以下几个区域: 1.方法区:方法区是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息.常量.静态变量.即时编译器编译后的代码等数据.虽然Java虚拟机规范把方法区描述为 ...
- tp5.0中使用PHPexcel,以及Loader的一些问题
在5.0中使用PHPexcel遇到一些问题,记录一下方便以后查看. 非使用PHPexcel的方法: 参考:http://blog.csdn.net/sinat_35861727/article/det ...
- 如何将Excel转换成Markdown表格[转]
在这篇文章中,我将告诉你如何快速的将Excel转换为markdown表格,以及如何将Google Docs,Numbers,网页中的表格或其他类似Excel的程序数据转换为Markdown表格 你可能 ...
- java知识点总结--java开发环境搭建
安装 JDK(Java Development Kit) 和开发工具 如:eclipse,myeclipse,idea等 配置系统环境变量 查看系统环境变量 1.通过 我的电脑--->“属性”- ...
- Python04(基础语法)
Trainning-day03回顾1.输出重定向 > 将输出到终端的内容输出到指定文件 命令 > 文件 注意: 1.如果文件存在,覆盖原文件 2.如果文件不存在,直接创建新文件2.输出追加 ...
- db.properties是干什么用的
连接池配置文件db.properties是java中采用数据库连接池技术完成应用对数据库的操作的配置文件信息的文件.具体配置项目如下:drivers=com.microsoft.sqlserver.j ...
- xargs处理来之STDIN的输入
xargs能够将标准输入进行处理,配合下一个命令进行批量处理 #example grep -f go.test ~/jqyou/genedhs_10D |sed '/-1$/d' |awk '{pri ...
- Arm11-mini6410入坑
Mini6410 学习Stm32的时候原子哥的资料真全啊,而且原子哥在他论坛也解答问题.然而现在学习ARM买了一套友善之臂的开发板,官方的资料只能刚好入门而已,其实入门都算不上.看了一下,网上的资料很 ...
- CnPack组件包的安装与使用
如果你用过Eclipse.NotePad++等等工具,再试试用刚装好Delphi写代码会很痛苦,你是否觉得Delphi的代码编辑器很不友好? 那就去了解一下CnPack吧,给你的Delphi装上它绝对 ...
- [C# 基础知识系列]专题五:当点击按钮时触发Click事件背后发生的事情 (转载)
当我们在点击窗口中的Button控件VS会帮我们自动生成一些代码,我们只需要在Click方法中写一些自己的代码就可以实现触发Click事件后我们Click方法中代码就会执行,然而我一直有一个疑问的—— ...