You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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; }
}

问题分析

  1. AddJsonStream是一次性读取配置,流释放后无法监听后续变更。
  2. 直接修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 02:19:53