XmlDocument 是最稳的配置节点读写方式,需用 AppDomain.CurrentDomain.BaseDirectory 拼出真实 MyApp.exe.config 路径,通过 SelectSingleNode 定位 appSettings 后增删改子节点,Save() 后必须调用 ConfigurationManager.RefreshSection("appSettings") 才生效。

用 XmlDocument 读取配置节点最稳,别碰 XElement.Load 直接改 App.config
直接操作应用程序的配置文件(如 App.config 或 Web.config)时,XmlDocument 是最可控的选择。很多人一上来就用 XElement.Load("App.config"),结果改完保存不了——因为运行时实际加载的是生成后的 MyApp.exe.config,路径和权限都对不上。
常见错误现象:System.UnauthorizedAccessException(写入被拒)、改完重启没生效、节点查不到但明明存在。
- 始终用
AppDomain.CurrentDomain.BaseDirectory拼出真实 config 路径:Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MyApp.exe.config") - 修改前先
doc.Load(configPath),别依赖ConfigurationManager的只读视图 - 写入必须调用
doc.Save(configPath),且确保进程有写权限(尤其在 Windows 10+ 默认安装到Program Files时)
appSettings 节点增删改要用 SelectSingleNode + CreateElement,别硬塞字符串
想加一个 <add key="Timeout" value="30"/>?千万别拼 XML 字符串再 InnerXml += ... —— 编码、转义、格式错位全得自己兜底,而且容易破坏原有缩进和声明。
正确做法是把 appSettings 当成普通 XML 节点操作:
- 用
doc.SelectSingleNode("/configuration/appSettings")定位父节点 - 新增:创建
XmlElement,设SetAttribute("key", "Timeout")和SetAttribute("value", "30"),再AppendChild - 修改:遍历
appSettings.SelectNodes("add"),匹配key属性后改value属性值 - 删除:找到目标节点后调用
ParentNode.RemoveChild(node)
示例片段:
var addNode = doc.CreateElement("add");
addNode.SetAttribute("key", "LogLevel");
addNode.SetAttribute("value", "Debug");
appSettings.AppendChild(addNode);
保存后 ConfigurationManager 不会自动刷新,手动调用 ConfigurationManager.RefreshSection
你改完了 appSettings 并 Save() 成功,但紧接着 ConfigurationManager.AppSettings["LogLevel"] 还是旧值——这不是缓存没清,是 .NET 根本没重载这个 section。
必须显式通知配置系统:“这部分我动过了,重新读一遍”:
- 只刷新对应 section:
ConfigurationManager.RefreshSection("appSettings") - 不能刷
"configuration"或空字符串,会无效 - 如果代码里还用了自定义配置节(比如
configSections下注册的),要刷对应节名,如"myCustomSection" - 注意:刷新只影响后续读取,已缓存的值(比如静态字段里存的)不会变
部署时 App.config 不是最终文件,真正起作用的是 .exe.config
开发时改 App.config 没问题,但发布后它会被复制为 MyApp.exe.config 并放在输出目录。所有运行时操作必须指向这个副本,而不是项目里的源文件。
容易被忽略的点:
- 调试时路径是
bin\Debug\MyApp.exe.config,发布后是publish\MyApp.exe.config - ClickOnce 应用更麻烦:config 文件可能被签名或压缩,直接写入会破坏部署包完整性
- 如果程序以管理员身份运行,但 config 在用户目录(如
%APPDATA%),路径和权限逻辑要单独处理 - 多线程同时写 config?没有内置锁,得自己加
lock或用临时文件 + 原子替换
事情说清了就结束


















