Reputation: 687
I want to use System.Runtime.Caching.MemoryCache
for caching some of my objects. I want to be sure that the object is refreshed once a day (absolute expiration) but I also want to make it expire if it hasn't been used in the last hour (sliding expiration).
I try to do:
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);
But I'm getting an error:
"ArgumentException" with "AbsoluteExpiration must be DateTimeOffset.MaxValue or SlidingExpiration must be TimeSpan.Zero."
Upvotes: 22
Views: 15069
Reputation: 316
A little additional notes to dieguitofernandez answer (which is btw, a very good solution):
The ChangeMonitor isn't fiering at the exact moment the AbsoluteExpiration is reached, because the Expiration isn't checked every second. It may take several seconds until the second cached item is notified. With 1 day as AbsoluteExpiration it doesn't matter, but if you need both expirations to be exact (like i did) you have to use both keys and the absolut-key first.
if (cache.Contains("Absolute" + key) && cache.Contains(key))
This way both expirations are checked immediately and you can be sure the item isn't expired.
(I could post this as comment because I'm new here, sorry!)
Upvotes: 2
Reputation: 116
You can implement both schemes cache expiration by using CacheEntryChangeMonitor. Insert a cache item without information with absolute expiration, then create a empty monitorChange with this item and link it with a second cache item, where you will actually save a slidingTimeOut information.
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);
Upvotes: 10
Reputation: 5132
You have two options:
MemoryCache
or it's parent ObjectCache
and implement your own caching mechanism.ChangeMonitor
which may be more difficult (see Note to Inheritors)Upvotes: 2
Reputation: 24558
A quick reflection with ILSpy show this code when calling MemoryCache.Add
if (policy.AbsoluteExpiration != ObjectCache.InfiniteAbsoluteExpiration && policy.SlidingExpiration != ObjectCache.NoSlidingExpiration)
{
throw new ArgumentException(R.Invalid_expiration_combination, "policy");
}
So, this combination of Absolute and Sliding Expiration is not supported natively.
You should turn yourself to a custom implementation.
Upvotes: 5
Reputation: 4296
DateTime.Now.AddDays(1)
doesn't return a DateTimeOffset, but a DateTime (AddDays()).
So it's most likely an invalid argument.
So instead, try DateTimeOffset.Now.AddDays(1)
(DateTimeOffset).
Upvotes: -2