ioptionsmonitor是唯一原生支持配置热更新的接口,但注入后拿不到新值的根本原因是底层iconfiguration未触发变更通知,常见于addjsonfile未设reloadonchange:true、内存/环境变量源不支持监听、linux下inotify限制或文件未复制到输出目录。

IOptionsMonitor
为什么 IOptionsMonitor 注入后还是拿不到新值
根本原因不是代码写错了,而是底层 IConfiguration 没触发变更通知。常见情况包括:
-
AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)忘了传reloadOnChange: true—— .NET 6+ 默认仍是false,仅 CLI 模板项目默认为true - 用
new ConfigurationBuilder().AddInMemoryCollection()构建配置,内存源天然不支持变更监听 -
AddEnvironmentVariables()或AddCommandLine()注入的配置,改环境变量或命令行参数不会触发通知 - 自定义
IConfigurationProvider没实现IChangeToken,或没在数据变更时调用OnReload()
验证方法:在 Program.cs 中临时加一行日志:configuration.GetReloadToken().RegisterChangeCallback(_ => Console.WriteLine("Config reloaded"));,保存配置文件后没输出,说明监听根本没建立。
appsettings.json 修改后 CurrentValue 不变的典型路径问题
.NET 只监听运行时输出目录(如 bin/Debug/net8.0/)下的文件,不是你编辑的源码目录里的 appsettings.json。所以:
- 检查
.csproj中该文件是否含<copytooutputdirectory>PreserveNewest</copytooutputdirectory> - 不要用记事本直接编辑
bin/下的文件——VS Code、Notepad++ 等可能加锁或原子写入,导致FileSystemWatcher收不到事件 - Linux/macOS/Docker 环境下,确认 inotify 未超限:
cat /proc/sys/fs/inotify/max_user_watches,容器中常需加--privileged或挂载/proc/sys/fs/inotify - 修改后等 500ms–2s 再查值,
FileSystemWatcher有延迟,且高频保存可能被合并为一次通知
IOptionsMonitor 的 OnChanged 回调要注意什么
回调函数不是“安全区”,它在任意线程执行,且不排队、不串行:
- 避免在回调里做 I/O、HTTP 请求或数据库操作,否则会阻塞后续配置更新
- 不要缓存
CurrentValue的引用并在多次回调中复用——每次回调拿到的是全新实例,旧引用已过期 - 需要更新 UI(如 WPF/WinForms)时,必须手动调度到主线程,不能直接操作控件
- 共享状态修改(如字典、标志位)要用
ConcurrentDictionary或加锁,别假设回调是单线程
安全做法是:回调中只做轻量通知(如 EventSource、Channel.Writer.TryWrite),把耗时逻辑交给后台任务处理。
配置类嵌套或集合变更后 CurrentValue 变成默认值
这不是监听失效,而是反序列化失败导致的静默回退——不会抛异常,字段直接取 default(T):
- JSON 字段名与 C# 属性名不匹配:默认启用
JsonNamingPolicy.CamelCase,但类里写了[JsonPropertyName("host")]却忘了加System.Text.Json引用,或用了Newtonsoft.Json但没配好序列化器 - 数值型字段填了空字符串或
null(如"TimeoutMs": ""),int绑定失败后变成0 - 嵌套对象层级错:JSON 中
"Plc:Host"要求类里有public PlcOptions Plc { get; set; },而不是public string PlcHost { get; set; } - 集合类型用
T[]而非List<t></t>或IEnumerable<t></t>,低版本 .NET 不支持数组反序列化
调试技巧:启动时打印 configuration.AsEnumerable() 全部键值对,确认你期望的完整路径(如 Plc:Host)确实存在且值非空。
热更新的“实时性”是假象,它依赖操作系统文件事件,不是魔法。最易被忽略的是:你以为改了 JSON 就生效,其实文件根本没落到运行目录,或者反序列化悄悄失败,而日志里连个警告都没有。










