对于ASP.NET Core MVC 项目,框架会自动注入内存缓存服务。对于 ASP.NET Web API 等需要手动注入内存缓存服务。
注入内存缓存服务:
builder.Services.AddMemoryCache();//注入内存缓存服务
内存缓存工具类接口:
using Microsoft.AspNetCore.Routing.Template; using Microsoft.Extensions.Caching.Memory; namespace TestWebApplication.Utility { public interface IMemoryCacheHelper { TResult? GetOrCreate<TResult>(string cacheKey, Func<ICacheEntry, TResult?> valueFactory, int expireSeconds = 60); /// <summary> /// 从内存缓存中获取数据,没有则通过委托方法从数据库中获取并设置缓存 /// </summary> /// <typeparam name="TResult"></typeparam> /// <param name="cacheKey">键</param> /// <param name="valueFactory">当缓存中不存在时,用此委托从数据库中获取</param> /// <param name="expireSeconds">多少秒后过期</param> /// <returns></returns> Task<TResult?> GetOrCreateAsync<TResult>(string cacheKey, Func<ICacheEntry, Task<TResult?>> valueFactory, int expireSeconds = 60); void Remove(string cacheKey); } }
实现:
using Microsoft.Extensions.Caching.Memory; namespace TestWebApplication.Utility { public class MemoryCacheHelper : IMemoryCacheHelper { private readonly IMemoryCache _cache; public MemoryCacheHelper(IMemoryCache cache) { _cache = cache; } private static void ValidateValueType<TResult>() { Type typeResult = typeof(TResult); if (typeResult.IsGenericType)//如果是泛型类型,获取泛型类型的定义 { typeResult = typeResult.GetGenericTypeDefinition(); } if (typeResult == typeof(IEnumerable<>) || typeResult == typeof(IEnumerable<TResult>) || typeResult == typeof(IAsyncEnumerable<TResult>) || typeResult == typeof(IQueryable<TResult>) || typeResult == typeof(IQueryable)) { throw new InvalidOperationException($"please use List<T> or T[] instead."); } } private static void InitCacheEntry(ICacheEntry entry, int baseExpireSeconds) { double sec = Random.Shared.Next(baseExpireSeconds, baseExpireSeconds * 2); TimeSpan expiration = TimeSpan.FromSeconds(sec); entry.AbsoluteExpirationRelativeToNow = expiration; } public TResult? GetOrCreate<TResult>(string cacheKey, Func<ICacheEntry, TResult?> valueFactory, int expireSeconds = 60) { throw new NotImplementedException(); } public async Task<TResult?> GetOrCreateAsync<TResult>(string cacheKey, Func<ICacheEntry, Task<TResult?>> valueFactory, int expireSeconds = 60) { ValidateValueType<TResult>(); if (_cache.TryGetValue(cacheKey, out TResult? result)==false) { using ICacheEntry entry = _cache.CreateEntry(cacheKey); InitCacheEntry(entry, expireSeconds); result = await valueFactory(entry); entry.Value = result; } return result; } public void Remove(string cacheKey) { _cache.Remove(cacheKey); } } }
客户端使用
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using TestWebApplication.Utility; namespace TestWebApplication { [Route("api/[controller]")] [ApiController] public class ValuesMemoryController : ControllerBase { private readonly ILogger<ValuesMemoryController> _logger; private readonly ApplicationDbContext _context; private readonly IMemoryCache _memoryCache; private readonly IMemoryCacheHelper _CacheHelper; public ValuesMemoryController(ILogger<ValuesMemoryController> logger, ApplicationDbContext context, IMemoryCache memoryCache, IMemoryCacheHelper cacheHelper) { _logger = logger; _context = context; _memoryCache = memoryCache; _CacheHelper = cacheHelper; } [HttpGet] public async Task<IEnumerable<PO>> GetPOs() { _logger.LogInformation($"开始执行{nameof(GetPOs)}:{DateTime.Now}"); //var items = await _memoryCache.GetOrCreateAsync("AllPO", async (e) => //{ // e.SlidingExpiration=TimeSpan.FromSeconds(10); // e.AbsoluteExpirationRelativeToNow=TimeSpan.FromSeconds(30); // _logger.LogInformation("从数据库中读取数据"); // return await _context.PO.Take(10).ToListAsync(); //}); var items = await _CacheHelper.GetOrCreateAsync("AllPO2", async (e) => { _logger.LogInformation("从数据库中读取数据"); return await _context.PO.Take(10).ToListAsync(); }, 10); _logger.LogInformation("把数据返回给调用者"); return items; } } }