NET6 使用MemoryCache

1.Nuget包

install-package Microsoft.Extensions.Caching.Memory -project xxxProjectName -version 7.0.0

2.封装类

2.1.ICacheService

/// <summary>
/// 缓存服务接口
/// </summary>
public interface ICacheService
{
    /// <summary>
    /// 获取缓存数据,如果不存在则执行委托方法获取数据并缓存
    /// </summary>
    /// <typeparam name="T">数据类型</typeparam>
    /// <param name="cacheKey">缓存键</param>
    /// <param name="cacheValue">缓存数据</param>
    /// <param name="absoluteExpiration">绝对过期时间</param>
    /// <param name="slidingExpiration">滑动过期时间</param>
    /// <param name="priority">设置缓存优先级</param>
    /// <returns>缓存的数据</returns>
    T GetOrCreate<T>(string cacheKey, T cacheValue, TimeSpan? absoluteExpiration = null, TimeSpan? slidingExpiration = null, CacheItemPriority priority = CacheItemPriority.Normal);

    /// <summary>
    /// 获取缓存数据,如果不存在则执行委托方法获取数据并缓存
    /// </summary>
    /// <param name="cacheKey">缓存键</param>
    /// <returns>item1:缓存中是否有值(true ? 有 : 没有);item2:缓存值</returns>
    Tuple<bool, T> Get<T>(string cacheKey);

    /// <summary>
    /// 移除指定缓存
    /// </summary>
    /// <param name="cacheKey">缓存键</param>
    void Remove(string cacheKey);

    /// <summary>
    /// 清空所有缓存
    /// </summary>
    void Clear();
}

2.2.MemoryCacheService

/// <summary>
/// .NET Core/.NET 6 框架内置的内存缓存实现
/// </summary>
public class MemoryCacheService : ICacheService
{
    /// <summary>
    /// 缓存
    /// </summary>
    private readonly IMemoryCache _memoryCache;

    /// <summary>
    /// 日志
    /// </summary>
    private readonly ILogger<MemoryCacheService> _logger;

    // 缓存键前缀,避免键冲突
    private const string CacheKeyPrefix = "Application:";

    /// <summary>
    /// 
    /// </summary>
    /// <param name="memoryCache"></param>
    /// <param name="logger"></param>
    public MemoryCacheService(IMemoryCache memoryCache, ILogger<MemoryCacheService> logger)
    {
        _memoryCache = memoryCache;
        _logger = logger;
    }

    /// <summary>
    /// 构建缓存key
    /// </summary>
    /// <param name="cacheKey"></param>
    /// <returns></returns>
    private string BuilderKey(string cacheKey) => $"{CacheKeyPrefix}:{cacheKey}";

    /// <summary>
    /// 获取缓存数据,如果不存在则执行委托方法获取数据并缓存
    /// </summary>
    /// <typeparam name="T">数据类型</typeparam>
    /// <param name="cacheKey">缓存键</param>
    /// <param name="cacheValue">缓存数据</param>
    /// <param name="absoluteExpiration">绝对过期时间</param>
    /// <param name="slidingExpiration">滑动过期时间</param>
    /// <returns>缓存的数据</returns>
    public T GetOrCreate<T>(string cacheKey, T cacheValue,
        TimeSpan? absoluteExpiration = null, TimeSpan? slidingExpiration = null
        , CacheItemPriority priority = CacheItemPriority.Normal)
    {
        // 尝试从缓存获取数据
        var getTuple = Get<T>(cacheKey);
        if (getTuple.Item1)
            return getTuple.Item2;

        // 添加前缀,避免不同模块缓存键冲突
        var key = BuilderKey(cacheKey);

        // 设置缓存选项
        var cacheEntryOptions = new MemoryCacheEntryOptions
        {
            PostEvictionCallbacks =
            {
                new PostEvictionCallbackRegistration
                {
                    // 回调方法
                    EvictionCallback = OnCacheEvicted,
                    // 可选:传递额外状态(会作为回调的state参数)
                    State = $"自定义状态:{key}"
                }
            }
        };

        // 设置过期时间(优先使用绝对过期,如果没有则使用滑动过期)
        if (absoluteExpiration.HasValue)
        {
            cacheEntryOptions.AbsoluteExpirationRelativeToNow = absoluteExpiration;
        }
        else if (slidingExpiration.HasValue)
        {
            cacheEntryOptions.SlidingExpiration = slidingExpiration;
        }
        else
        {
            // 默认绝对过期时间:30分钟
            cacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
        }

        // 设置缓存优先级(避免内存不足时被优先移除)
        cacheEntryOptions.Priority = priority;
        // 存入缓存
        _memoryCache.Set(key, cacheValue, cacheEntryOptions);

        return cacheValue;
    }

    /// <summary>
    /// 缓存被驱逐时执行的回调方法
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <param name="reason"></param>
    /// <param name="state"></param>
    private void OnCacheEvicted(object key, object value, EvictionReason reason, object state)
    {
        // 可以在这里处理过期逻辑(如记录日志、更新数据库等)
        var sb = new StringBuilder();
        sb.Append($"缓存项被驱逐:");
        sb.Append($" Key: {key}");
        sb.Append($" Value: {value}");
        sb.Append($" 原因:{reason}"); // 过期、移除、替换、内存压力等
        sb.Append($" 状态:{state}");
        _logger.LogInformation(sb.ToString());
    }

    /// <summary>
    /// 获取缓存数据,如果不存在则执行委托方法获取数据并缓存
    /// </summary>
    /// <typeparam name="T">数据类型</typeparam>
    /// <param name="cacheKey">缓存键</param>
    /// <returns>缓存的数据</returns>
    public Tuple<bool, T> Get<T>(string cacheKey)
    {
        // 添加前缀,避免不同模块缓存键冲突
        var key = BuilderKey(cacheKey);

        // 尝试从缓存获取数据
        var boo = _memoryCache.TryGetValue(key, out T cachedData);
        return boo ? new Tuple<bool, T>(true, cachedData) : new Tuple<bool, T>(false, default);
    }

    /// <summary>
    /// 移除指定缓存
    /// </summary>
    /// <param name="cacheKey">缓存键</param>
    public void Remove(string cacheKey)
    {
        var key = BuilderKey(cacheKey);
        _memoryCache.Remove(key);
    }

    /// <summary>
    /// 清空所有缓存
    /// </summary>
    public void Clear()
    {
        // IMemoryCache没有直接清空的方法,这里通过创建新的缓存实例来实现
        // 注意:这种方式需要结合自定义的缓存管理
        // 实际应用中,通常不需要完全清空,而是按需移除
    }
}

3.注册服务

var builder = WebApplication.CreateBuilder(args);

// 添加.NET 6内置的内存缓存服务
builder.Services.AddMemoryCache();

// 注册自定义缓存服务和业务服务
builder.Services.AddSingleton<ICacheService, MemoryCacheService>();

var app = builder.Build();

// 其他中间件配置...

app.Run();

 

PS:

1.IMemoryCache是进程内缓存,不适用于多服务器部署场景
2.缓存数据量不宜过大,以免影响应用性能
3.对于频繁变化的数据,应设置较短的过期时间
4.内存缓存会在应用重启后丢失,需要重新加载

 

posted @ 2025-08-27 14:16  Robot-Blog  阅读(17)  评论(0)    收藏  举报