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

如何在ASP.NET Core中实现自动刷新的高效本地缓存系统?

在ASP.NET Core中实现带自动刷新的本地缓存方案

核心方案

利用ASP.NET Core原生的IMemoryCache存储缓存数据,搭配后台定时任务(基于BackgroundService)定期刷新缓存。刷新时遵循「先获取新数据,再替换旧缓存」的原则,同时用锁机制避免重复触发刷新操作,确保请求始终能拿到有效数据,不会出现空窗期。

具体实现步骤

1. 定义数据获取接口(模拟外部数据源)

先封装外部数据的获取逻辑,方便后续替换和测试:

public interface IDataProvider
{
    // 模拟从API/数据库获取最新数据
    Task<MyDataModel> GetLatestDataAsync();
}

public class DataProvider : IDataProvider
{
    public async Task<MyDataModel> GetLatestDataAsync()
    {
        // 这里替换为实际的外部数据源调用逻辑
        await Task.Delay(100); // 模拟IO耗时
        return new MyDataModel
        {
            Id = Guid.NewGuid(),
            Content = $"最新数据:{DateTime.Now:yyyy-MM-dd HH:mm:ss}",
            LastUpdated = DateTime.Now
        };
    }
}

// 数据模型示例
public class MyDataModel
{
    public Guid Id { get; set; }
    public string Content { get; set; }
    public DateTime LastUpdated { get; set; }
}

2. 实现后台缓存刷新服务

创建一个后台服务,负责定时刷新缓存,同时用SemaphoreSlim防止并发刷新:

public class CacheRefreshService : BackgroundService
{
    private readonly IMemoryCache _cache;
    private readonly IDataProvider _dataProvider;
    private readonly SemaphoreSlim _refreshLock = new SemaphoreSlim(1, 1);
    private readonly TimeSpan _refreshInterval = TimeSpan.FromMinutes(5); // 5分钟刷新一次

    public CacheRefreshService(IMemoryCache cache, IDataProvider dataProvider)
    {
        _cache = cache;
        _dataProvider = dataProvider;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // 启动时先初始化缓存
        await RefreshCacheAsync();

        while (!stoppingToken.IsCancellationRequested)
        {
            await Task.Delay(_refreshInterval, stoppingToken);
            await RefreshCacheAsync();
        }
    }

    private async Task RefreshCacheAsync()
    {
        // 确保同一时间只有一个刷新任务执行
        if (!await _refreshLock.WaitAsync(TimeSpan.FromSeconds(5)))
        {
            return; // 如果5秒内拿不到锁,放弃本次刷新,避免阻塞
        }

        try
        {
            // 先获取最新数据,再替换缓存——避免缓存空窗期
            var latestData = await _dataProvider.GetLatestDataAsync();
            _cache.Set("CachedData:Latest", latestData);
        }
        finally
        {
            _refreshLock.Release();
        }
    }
}

3. 注册服务到DI容器

在Program.cs中注册数据提供器和后台刷新服务:

var builder = WebApplication.CreateBuilder(args);

// 注册数据提供器
builder.Services.AddScoped<IDataProvider, DataProvider>();
// 注册后台缓存刷新服务
builder.Services.AddHostedService<CacheRefreshService>();
// MemoryCache默认已注册,无需额外添加

// 添加控制器
builder.Services.AddControllers();

var app = builder.Build();

app.MapControllers();
app.Run();

4. 在业务逻辑中使用缓存

在控制器或服务中直接从IMemoryCache获取数据,因为后台服务已经维护了最新的缓存:

[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
    private readonly IMemoryCache _cache;

    public DataController(IMemoryCache cache)
    {
        _cache = cache;
    }

    [HttpGet]
    public IActionResult GetCachedData()
    {
        if (_cache.TryGetValue("CachedData:Latest", out MyDataModel data))
        {
            return Ok(data);
        }
        // 理论上不会走到这里,因为启动时已经初始化了缓存
        return StatusCode(StatusCodes.Status503ServiceUnavailable, "缓存未初始化");
    }
}

关键细节说明

  • 避免缓存空窗期:刷新时先获取新数据,再覆盖旧缓存,确保请求始终能拿到有效数据,不会出现缓存失效后等待新数据的情况。
  • 防止并发刷新:用SemaphoreSlim控制刷新操作,避免多个刷新任务同时执行,减少对外部数据源的压力。
  • 初始化缓存:后台服务启动时立即执行一次刷新,确保缓存一开始就有数据,避免首次请求无缓存可用。
  • 可配置性:可以把刷新间隔放到配置文件(如appsettings.json)中,通过IOptions<T>读取,方便调整。

内容的提问来源于stack exchange,提问作者ياسمين يعقوبي

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 17:43:13