Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.net Cache Absolute Expiration not working

I am storing a single integer value in HttpContext.Cache with an absolute expiration time of 5 minutes from now. However, after waiting 6 minutes (or longer), the integer value is still in the Cache (i.e. it's never removed even though the absolute expiration has passed). Here is the code I am using:

public void UpdateCountFor(string remoteIp)
{
    // only returns true the first time its run
    // after that the value is still in the Cache
    // even after the absolute expiration has passed
    // so after that this keeps returning false
    if (HttpContext.Current.Cache[remoteIp] == null)
    {
        // nothing for this ip in the cache so add the ip as a key with a value of 1
        var expireDate = DateTime.Now.AddMinutes(5);
        // I also tried:
        // var expireDate = DateTime.UtcNow.AddMinutes(5); 
        // and that did not work either.
        HttpContext.Current.Cache.Insert(remoteIp, 1, null, expireDate, Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
    }
    else
    {
        // increment the existing value
        HttpContext.Current.Cache[remoteIp] = ((int)HttpContext.Current.Cache[remoteIp]) + 1;
    }
}

The first time I run UpdateCountFor("127.0.0.1") it inserts 1 into the cache with key "127.0.0.1" and an absolute expiration of 5 minutes from now as expected. Every subsequent run then increments the value in the cache. However, after waiting 10 minutes it continues to increment the value in the Cache. The value never expires and never gets removed from the Cache. Why is that?

It's my understanding that an absolute expiration time means the item will get removed approximately at that time. Am I doing something wrong? Am I misunderstanding something?

I'm expecting the value to be removed from the Cache after 5 minutes time, however it stays in there until I rebuild the project.

This is all running on .NET 4.0 on my local machine.

like image 802
smoak Avatar asked May 05 '11 18:05

smoak


2 Answers

It turns out that this line:

HttpContext.Current.Cache[remoteIp] = ((int)HttpContext.Current.Cache[remoteIp]) + 1;

removes the previous value and re-inserts the value with NO absolute or sliding expiration time. In order to get around this I had to create a helper class and use it like so:

public class IncrementingCacheCounter
{
    public int Count;
    public DateTime ExpireDate;
}

public void UpdateCountFor(string remoteIp)
{
    IncrementingCacheCounter counter = null;
    if (HttpContext.Current.Cache[remoteIp] == null)
    {
        var expireDate = DateTime.Now.AddMinutes(5);
        counter = new IncrementingCacheCounter { Count = 1, ExpireDate = expireDate };
    }
    else
    {
        counter = (IncrementingCacheCounter)HttpContext.Current.Cache[remoteIp];
        counter.Count++;
    }
    HttpContext.Current.Cache.Insert(remoteIp, counter, null, counter.ExpireDate, Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
}

This will get around the issue and let the counter properly expire at the absolute time while still enabling updates to it.

like image 92
smoak Avatar answered Oct 03 '22 17:10

smoak


Try using DateTime.UtcNow to calculate your timeout period instead of datetime.Now . You may be running into the issue described below:

absoluteExpiration Type: System.DateTime The time at which the inserted object expires and is removed from the cache. To avoid possible issues with local time such as changes from standard time to daylight saving time, use UtcNow rather than Now for this parameter value. If you are using absolute expiration, the slidingExpiration parameter must be NoSlidingExpiration.

like image 30
Chris Mullins Avatar answered Oct 03 '22 19:10

Chris Mullins