IOptionsMonitor不生效的主因是配置源未启用变更监听,如AddJsonFile需显式设reloadOnChange:true,内存集合、环境变量等原生不支持热更新;Linux下还需调高inotify限制。

为什么 IOptionsMonitor 不生效?常见配置源没启用变更监听
直接注入 IOptionsMonitor<MyConfig> 却收不到更新,大概率是底层配置源不支持热重载。比如手动用 new ConfigurationBuilder().AddInMemoryCollection() 构建的配置,默认不会触发变更;appsettings.json 虽然默认开启,但前提是调用了 AddJsonFile(..., reloadOnChange: true)。
-
reloadOnChange: true必须显式传入,.NET 6+ 默认仍是false(仅 CLI 模板项目默认为true) - 自定义
IConfigurationProvider必须实现IChangeToken并在数据变更时调用OnReload() -
AddEnvironmentVariables()和AddCommandLine()原生不支持热更新,改环境变量或命令行参数不会触发IOptionsMonitor回调
IOptionsMonitor 的回调时机和线程安全要注意什么?
每次配置变更后,IOptionsMonitor<T> 会立即重建实例并触发所有注册的 IOptionssSnapshot<T> 监听器(通过 OnChange),但这个过程不是线程安全的——回调函数可能在任意线程执行,且多个变更可能快速连续触发。
- 不要在
OnChange回调里做耗时操作(如 I/O、HTTP 请求),否则会阻塞后续配置更新 - 避免在回调中直接修改共享状态,建议用
ConcurrentDictionary或加锁;若需 UI 更新(如 WPF/WinForms),要手动调度到主线程 - 回调中调用
CurrentValue是安全的,它返回的是已构建好的新实例;但不要缓存该引用并跨多次回调复用——下次变更后它就过期了
如何让自定义配置类也响应热更新?别忘了 [NotifyPropertyChanged] 和属性 setter
IOptionsMonitor 本身不监听对象内部属性变化,它只在配置源整体刷新时重建整个对象。如果你希望某个属性变更(比如 JSON 文件里一个字段被改)能立刻被业务逻辑感知,光靠 IOptionsMonitor 不够,得配合 INotifyPropertyChanged。
- 配置类需实现
INotifyPropertyChanged,并在每个属性 setter 中调用PropertyChanged?.Invoke() - 不能依赖自动属性(
public string Name { get; set; }),必须写完整 setter,否则变更无法通知 - 如果使用
System.Text.Json反序列化,确保属性有 public setter;用JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase时,也要保证 JSON 字段名匹配 - 示例:
public class ApiSettings : INotifyPropertyChanged { private string _baseUrl; public string BaseUrl { get => _baseUrl; set { if (_baseUrl != value) { _baseUrl = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(BaseUrl))); } } } public event PropertyChangedEventHandler? PropertyChanged; }
开发时文件监控失效?检查 dotnet watch 和文件系统事件权限
本地跑 dotnet watch run 时配置没更新,常见原因是文件系统监控未就绪:Linux/macOS 上 inotify 限制太低,Windows 上杀毒软件拦截,或者 VS Code 的文件保存行为(如“save after delay”)导致变更未真正落盘。
- Linux 下临时提高限制:
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p - VS Code 用户检查设置:
"files.autoSave": "onFocusChange"或禁用"files.useExperimentalFileWatcher" - 用
dotnet watch --verbose查看是否输出watching for changes...和change detected日志 - 注意:
dotnet watch默认只监听**/*.cs和**/appsettings*.json,若配置文件名不匹配(如config.dev.json),需手动加--watch参数指定路径


















