上边我们已经简单了解了通过滑动过期时间和绝对过期时间来控制缓存的有效性,但是有时缓存的过期与否和时间没有联系,比如我们缓存一个文件的内容,不管缓存多久只要文件没有发生变化缓存都是有效的。在net framework中我们可以通过CacheDependency来控制,在net core中怎么控制呢?net core中我们可以使用IChangeToken接口轻松实现缓存的过期策略。先看一下IChangeToken接口:
public interface IChangeToken { // 是否有变化发生 bool HasChanged { get; } // token是否会调用回调函数,为true时才会有效 bool ActiveChangeCallbacks { get; } // 注册一个回调函数,当有变化时触发回调 IDisposable RegisterChangeCallback(Action<object> callback, object state); }
看一下IChangeToken实现缓存过期策略的两个例子
1.3.1 监控文件
需要安装组件:Microsoft.Extensions.FileProviders.Physical
internal class Program { private static void Main(string[] args) { string fileName = Path.Combine(Environment.CurrentDirectory, "someCacheData.xml"); var fileInfo = new FileInfo(fileName); MemoryCache myCache = new MemoryCache(new MemoryCacheOptions() { }); MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions(); //PollingFileChangeToken是IChangeToken的实现类,通过轮询监控文件变化 cacheEntityOps.AddExpirationToken(new Microsoft.Extensions.FileProviders.Physical.PollingFileChangeToken(fileInfo)); //缓存失效时,回调函数 cacheEntityOps.RegisterPostEvictionCallback((key, value, reason, state) => { Console.WriteLine($"文件【{key}】改动了"); }); //添加缓存,key为文件名,value为文件内容 myCache.Set(fileInfo.Name, File.ReadAllText(fileName), cacheEntityOps); Console.WriteLine(myCache.Get(fileInfo.Name)); } }
PollingFileChangeToken通过轮询来监控文件有没有发生变化,如果文件中的内容发生改变,缓存就会自动过期。
1.3.2 通过代码控制缓存过期
class Program { static void Main(string[] args) { MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions()); MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions(); //使用CancellationChangeToken控制缓存过期 CancellationTokenSource tokenSource = new CancellationTokenSource(); cacheEntityOps.AddExpirationToken(new CancellationChangeToken(tokenSource.Token)); //设置缓存 memoryCache.Set("mykey", "myvalue", cacheEntityOps); Console.WriteLine(memoryCache.Get("mykey") ?? "缓存被清除了"); //通过代码清除缓存 tokenSource.Cancel(); Console.WriteLine(memoryCache.Get("mykey") ?? "缓存被清除了"); } }
tokenSource.Cancel方法发送取消信号,这个方法会触发缓存过期,基于此我们可以通过Cancel方法灵活的实现自定义的缓存策略。
程序执行结果如下:
1.4 引用Nuget包直接引用我自己简单封装的一个Nuget包(简单封装自己用,不要嘲笑)
<PackageReference Include="Common.Cache.MemoryCache" Version="1.1.0" />
注入到容器
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); //注入 services.AddMemoryCacheExtension(); }
使用
# 在需要使用的地方进行注入 private readonly IMemoryCachimg _cache; public HomeController(IMemoryCachimg cache) { _cache = cache; }