结合滑动和绝对到期

本文关键字:结合 | 更新日期: 2023-09-27 18:13:22

我想使用System.Runtime.Caching.MemoryCache缓存我的一些对象。我想确保对象每天刷新一次(绝对过期),但我也想让它过期,如果它在最后一个小时内没有使用(滑动过期)。我试着做:

object item = "someitem";
var cache = MemoryCache.Default;
var policy = new CacheItemPolicy();
policy.AbsoluteExpiration = DateTime.Now.AddDays(1);
policy.SlidingExpiration = TimeSpan.FromHours(1);
cache.Add("somekey", item, policy);

但是我得到一个错误:

"ArgumentException"必须带有"AbsoluteExpirationDateTimeOffset。MaxValue或SlidingExpiration必须为TimeSpan.Zero."

结合滑动和绝对到期

可以通过使用CacheEntryChangeMonitor来实现这两种方案的缓存过期。插入一个没有绝对过期信息的缓存项,然后用这个项创建一个空的monitorChange,并将它与第二个缓存项链接,在这个缓存项中,您将实际保存一个slidingTimeOut信息。

        object data = new object();
        string key = "UniqueIDOfDataObject";
        //Insert empty cache item with absolute timeout
        string[] absKey = { "Absolute" + key };
        MemoryCache.Default.Add("Absolute" + key, new object(), DateTimeOffset.Now.AddMinutes(10));
        //Create a CacheEntryChangeMonitor link to absolute timeout cache item
        CacheEntryChangeMonitor monitor = MemoryCache.Default.CreateCacheEntryChangeMonitor(absKey);
        //Insert data cache item with sliding timeout using changeMonitors
        CacheItemPolicy itemPolicy = new CacheItemPolicy();
        itemPolicy.ChangeMonitors.Add(monitor);
        itemPolicy.SlidingExpiration = new TimeSpan(0, 60, 0);
        MemoryCache.Default.Add(key, data, itemPolicy, null);

在调用MemoryCache.Add

时使用ILSpy快速反射显示此代码
if (policy.AbsoluteExpiration != ObjectCache.InfiniteAbsoluteExpiration && policy.SlidingExpiration != ObjectCache.NoSlidingExpiration)
    {
        throw new ArgumentException(R.Invalid_expiration_combination, "policy");
    }

因此,本机不支持绝对过期和滑动过期的组合。

您应该转向自定义实现

您有两个选择:

  1. 继承MemoryCache或它的父ObjectCache,并实现自己的缓存机制。
  2. 实现ChangeMonitor,这可能会更困难(见继承者注意事项)

对dieguitoffernandez的回答(顺便说一句,这是一个非常好的解决方案)的一点额外说明:

ChangeMonitor没有在达到AbsoluteExpiration的确切时刻发出警报,因为没有每秒钟检查一次Expiration。可能需要几秒钟的时间才能通知第二个缓存项。用1天作为AbsoluteExpiration没关系,但是如果你需要两个到期时间都是精确的(就像我一样),你必须首先使用两个键和绝对键。

if (cache.Contains("Absolute" + key) && cache.Contains(key))

这样可以立即检查两个过期时间,您可以确定项目没有过期。

(我可以把这个作为评论,因为我是新来的,抱歉!)

DateTime.Now.AddDays(1)不返回DateTimeOffset,而是DateTime (AddDays())。

所以它很可能是一个无效参数

所以,试试DateTimeOffset.Now.AddDays(1) (DateTimeOffset)。