如何使用IOptionsMonitor获取并监听内存中的配置变更
使用IOptionsMonitor监听内存配置变更的实现方案
我希望在C#中使用IOptionsMonitor来获取并监听存储在内存中的配置变更。我了解IOptionsMonitor通常用于读取文件系统或环境变量的配置,并在变更时通知应用,但我的需求是在运行时动态更新内存中的配置,同时让IOptionsMonitor感知到这些变更。
是否可以设置自定义内存配置源,让IOptionsMonitor监听这些内存配置的变更?如果可以,能否提供简单示例或实现指引?
我参考微软文档示例并修改为使用MemoryStream,但读取配置后释放了流,关闭的流显然无法持续监听变更。我直接修改IConfiguration也没有任何效果。
原尝试代码(存在的问题)
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); using (MemoryStream memoryStream = new MemoryStream()) using (StreamWriter writer = new StreamWriter(memoryStream)) { string json = """ { "SecretKey": "Secret key value", "TransientFaultHandlingOptions": { "Enabled": true, "AutoRetryDelay": "00:00:07" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } } } """; writer.Write(json); writer.Flush(); memoryStream.Position = 0; builder.Configuration.AddJsonStream(writer.BaseStream); } string className = nameof(TransientFaultHandlingOptions); builder.Services.Configure<TransientFaultHandlingOptions>(builder.Configuration.GetSection(className)); builder.Services.AddSingleton<MonitorService>(); using IHost host = builder.Build(); IConfiguration? con = host.Services.GetRequiredService<IConfiguration>(); var rs = con.GetRequiredSection(className); MonitorService Monitor = host.Services.GetRequiredService<MonitorService>(); Monitor.DisplayValues(); rs["AutoRetryDelay"] = "01:23:45"; rs["AutoRetryDelay"] = "01:02:03"; rs["AutoRetryDelay"] = "66:55:44"; public sealed class MonitorService(IOptionsMonitor<TransientFaultHandlingOptions> monitor) { public void DisplayValues() { TransientFaultHandlingOptions options = monitor.CurrentValue; monitor.OnChange(Change); Console.WriteLine($"TransientFaultHandlingOptions.Enabled={options.Enabled}"); Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}"); } static void Change(TransientFaultHandlingOptions options) { Console.WriteLine($"FromChange : TransientFaultHandlingOptions.Enabled={options.Enabled}"); Console.WriteLine($"FromChange : TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}"); } } public sealed class TransientFaultHandlingOptions { public bool Enabled { get; set; } public TimeSpan AutoRetryDelay { get; set; } }
问题分析
AddJsonStream是一次性读取配置,流释放后无法监听后续变更。- 直接修改
IConfiguration的Section值不会触发变更通知——默认配置提供者不支持主动推送变更事件。
解决方案:自定义内存配置源与提供者
要实现内存配置的动态更新并让IOptionsMonitor感知到,需要实现支持变更通知的自定义配置源和提供者:
1. 实现自定义内存配置提供者和源
public class MemoryConfigurationProvider : ConfigurationProvider { private readonly Dictionary<string, string?> _configData; public MemoryConfigurationProvider(Dictionary<string, string?> initialData) { _configData = initialData ?? new Dictionary<string, string?>(); Load(); } public override void Load() { Data = new Dictionary<string, string?>(_configData, StringComparer.OrdinalIgnoreCase); } // 更新单个配置项并触发变更 public void UpdateConfiguration(string key, string? value) { if (Data.TryGetValue(key, out var existingValue) && existingValue == value) return; Data[key] = value; OnReload(); } // 批量更新配置项并触发变更 public void UpdateConfiguration(Dictionary<string, string?> updates) { bool changed = false; foreach (var (key, value) in updates) { if (Data.TryGetValue(key, out var existingValue) && existingValue == value) continue; Data[key] = value; changed = true; } if (changed) OnReload(); } } public class MemoryConfigurationSource : IConfigurationSource { public Dictionary<string, string?> InitialData { get; set; } = new(); public IConfigurationProvider Build(IConfigurationBuilder builder) { return new MemoryConfigurationProvider(InitialData); } }
2. 扩展方法简化配置源添加
public static class ConfigurationBuilderExtensions { public static IConfigurationBuilder AddMemoryConfiguration( this IConfigurationBuilder builder, Dictionary<string, string?> initialData) { builder.Add(new MemoryConfigurationSource { InitialData = initialData }); return builder; } }
3. 完整使用示例
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); // 初始化内存配置数据(用冒号分隔层级,对应JSON结构) var initialConfig = new Dictionary<string, string?> { ["SecretKey"] = "Secret key value", ["TransientFaultHandlingOptions:Enabled"] = "true", ["TransientFaultHandlingOptions:AutoRetryDelay"] = "00:00:07", ["Logging:LogLevel:Default"] = "Information", ["Logging:LogLevel:Microsoft"] = "Warning", ["Logging:LogLevel:Microsoft.Hosting.Lifetime"] = "Information" }; // 添加自定义内存配置源 builder.Configuration.AddMemoryConfiguration(initialConfig); string className = nameof(TransientFaultHandlingOptions); builder.Services.Configure<TransientFaultHandlingOptions>(builder.Configuration.GetSection(className)); builder.Services.AddSingleton<MonitorService>(); using IHost host = builder.Build(); // 获取自定义内存配置提供者 var memoryProvider = host.Services.GetRequiredService<IConfiguration>() .Providers.OfType<MemoryConfigurationProvider>().First(); MonitorService monitorService = host.Services.GetRequiredService<MonitorService>(); monitorService.DisplayValues(); // 动态更新配置,触发IOptionsMonitor的变更通知 memoryProvider.UpdateConfiguration("TransientFaultHandlingOptions:AutoRetryDelay", "01:23:45"); await Task.Delay(100); // 等待变更通知处理 memoryProvider.UpdateConfiguration("TransientFaultHandlingOptions:AutoRetryDelay", "01:02:03"); await Task.Delay(100); memoryProvider.UpdateConfiguration(new Dictionary<string, string?> { ["TransientFaultHandlingOptions:Enabled"] = "false", ["TransientFaultHandlingOptions:AutoRetryDelay"] = "66:55:44" }); await host.RunAsync(); public sealed class MonitorService(IOptionsMonitor<TransientFaultHandlingOptions> monitor) { public void DisplayValues() { TransientFaultHandlingOptions options = monitor.CurrentValue; monitor.OnChange(Change); Console.WriteLine($"初始值: TransientFaultHandlingOptions.Enabled={options.Enabled}"); Console.WriteLine($"初始值: TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}"); } static void Change(TransientFaultHandlingOptions options) { Console.WriteLine($"变更后: TransientFaultHandlingOptions.Enabled={options.Enabled}"); Console.WriteLine($"变更后: TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}"); } } public sealed class TransientFaultHandlingOptions { public bool Enabled { get; set; } public TimeSpan AutoRetryDelay { get; set; } }
关键说明
- 自定义
MemoryConfigurationProvider通过OnReload()方法触发配置变更通知,这是让IOptionsMonitor感知到变更的核心。 - 配置键使用冒号(
:)分隔层级,与JSON配置结构对应,确保IOptions绑定正常工作。 - 必须通过自定义提供者的
UpdateConfiguration方法更新配置,而非直接修改IConfiguration,这样才能触发变更通知。
内容的提问来源于stack exchange,提问作者zms9110750
相关产品推荐
相关产品推荐

