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

ASP.NET Core如何定时从DB/缓存更新配置并兼容本地配置?

现有配置与初始化代码

appsettings.json 配置

// settings for allowing access from other services
"AuthSetting": {
  "CookieAuthSetting": {
      "KeyForAccessingFromServiceZ": {
             "ServiceName": "ServiceZ",
             "DeveloperName": "dev1",
         },
  "IPAuthSetting": {
              "IPWhiteList": ["aaa.aaa.aaa.aaa", "bbb.bbb.bbb.bbb"],
              "IPBlackList": ["ccc.ccc.ccc.ccc"]
         }
  }
},
// key for access to other service
"Neighbors": {
  "ServiceY": "KeyforAccessToY"
}

Startup.cs 初始化代码

services.Configure<AuthSetting>(Configuration.GetSection(nameof(AuthSetting)));
services.Configure<Neighbors>(Configuration.GetSection(nameof(Neighbors)));

实现方案

1. 定时刷新认证配置

使用BackgroundService实现定时任务,定期从远端存储拉取最新配置并更新应用内的配置实例。

核心代码

后台刷新服务类

public class AuthConfigRefreshService : BackgroundService
{
    private readonly IOptionsMonitor<AuthSetting> _authSettingMonitor;
    private readonly IOptionsMonitor<Neighbors> _neighborsMonitor;
    private readonly IAuthConfigRepository _authConfigRepo;
    private readonly PeriodicTimer _timer;

    public AuthConfigRefreshService(
        IOptionsMonitor<AuthSetting> authSettingMonitor,
        IOptionsMonitor<Neighbors> neighborsMonitor,
        IAuthConfigRepository authConfigRepo)
    {
        _authSettingMonitor = authSettingMonitor;
        _neighborsMonitor = neighborsMonitor;
        _authConfigRepo = authConfigRepo;
        _timer = new PeriodicTimer(TimeSpan.FromMinutes(5)); // 可通过配置文件调整刷新间隔
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested && await _timer.WaitForNextTickAsync(stoppingToken))
        {
            try
            {
                // 从数据库/缓存/RPC拉取最新配置
                var latestAuth = await _authConfigRepo.GetLatestAuthSettingAsync();
                var latestNeighbors = await _authConfigRepo.GetLatestNeighborsAsync();

                // 触发配置更新,依赖IOptionsMonitor的组件会自动获取最新值
                _authSettingMonitor.OnChange(_ => latestAuth);
                _neighborsMonitor.OnChange(_ => latestNeighbors);
            }
            catch (Exception ex)
            {
                // 记录刷新失败日志,不中断服务
                // _logger.LogError(ex, "Auth config refresh failed");
            }
        }
    }

    public override void Dispose()
    {
        _timer.Dispose();
        base.Dispose();
    }
}

注册服务

在Program.cs/Startup.cs中注册后台服务和仓储:

services.AddHostedService<AuthConfigRefreshService>();
services.AddScoped<IAuthConfigRepository, AuthConfigRepository>();

仓储接口示例

public interface IAuthConfigRepository
{
    Task<AuthSetting> GetLatestAuthSettingAsync();
    Task<Neighbors> GetLatestNeighborsAsync();
}

// 实现类根据实际存储介质编写(比如Redis、EF Core、内部RPC调用)
public class AuthConfigRepository : IAuthConfigRepository
{
    // 构造函数注入数据库/缓存客户端
    public AuthConfigRepository(IConfiguration config)
    {
        // 初始化客户端
    }

    public async Task<AuthSetting> GetLatestAuthSettingAsync()
    {
        // 从远端拉取逻辑,比如从Redis获取反序列化,或者数据库查询
        return await Task.FromResult(new AuthSetting());
    }

    public async Task<Neighbors> GetLatestNeighborsAsync()
    {
        // 同理实现远端拉取逻辑
        return await Task.FromResult(new Neighbors());
    }
}

2. 优先加载本地配置,兼容远端故障

启动时优先绑定本地appsettings.json的配置,再尝试拉取远端配置;若远端拉取失败,直接保留本地配置,不影响服务启动。

核心代码(Program.cs 示例)

var builder = WebApplication.CreateBuilder(args);

// 1. 加载本地配置
var localAuth = new AuthSetting();
builder.Configuration.GetSection(nameof(AuthSetting)).Bind(localAuth);
var localNeighbors = new Neighbors();
builder.Configuration.GetSection(nameof(Neighbors)).Bind(localNeighbors);

// 2. 尝试拉取远端配置,失败则跳过
try
{
    var authRepo = new AuthConfigRepository(builder.Configuration);
    var remoteAuth = await authRepo.GetLatestAuthSettingAsync();
    var remoteNeighbors = await authRepo.GetLatestNeighborsAsync();

    // 合并远端与本地配置(冲突处理逻辑见下文)
    MergeAuthConfigs(localAuth, remoteAuth);
    MergeNeighborConfigs(localNeighbors, remoteNeighbors);
}
catch (Exception ex)
{
    // 记录日志,继续使用本地配置
    // builder.Logging.LogError(ex, "Failed to load remote auth config, falling back to local");
}

// 3. 注册合并后的配置
builder.Services.Configure<AuthSetting>(_ => localAuth);
builder.Services.Configure<Neighbors>(_ => localNeighbors);

// 其他服务注册...
var app = builder.Build();
// 管道配置...
app.Run();

3. 配置合并:本地优先加载,冲突时远端覆盖

实现自定义合并逻辑,确保本地配置先加载,远端配置覆盖同名条目、新增条目追加。

合并逻辑示例

// 合并AuthSetting
private void MergeAuthConfigs(AuthSetting local, AuthSetting remote)
{
    if (remote == null) return;

    // CookieAuthSetting:远端条目覆盖本地同名,新增条目添加
    if (remote.CookieAuthSetting != null)
    {
        foreach (var entry in remote.CookieAuthSetting)
        {
            local.CookieAuthSetting[entry.Key] = entry.Value;
        }
    }

    // IPAuthSetting:远端配置直接覆盖本地(按需求,冲突以远端为准)
    if (remote.IPAuthSetting != null)
    {
        local.IPAuthSetting.IPWhiteList = remote.IPAuthSetting.IPWhiteList ?? local.IPAuthSetting.IPWhiteList;
        local.IPAuthSetting.IPBlackList = remote.IPAuthSetting.IPBlackList ?? local.IPAuthSetting.IPBlackList;
    }
}

// 合并Neighbors
private void MergeNeighborConfigs(Neighbors local, Neighbors remote)
{
    if (remote == null) return;

    foreach (var serviceEntry in remote)
    {
        local[serviceEntry.Key] = serviceEntry.Value;
    }
}

内容的提问来源于stack exchange,提问作者Panic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 04:09:53