Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the expiry datetime of an HttpRuntime.Cache object?

Is it possible to get the expiry DateTime of an HttpRuntime.Cache object?

If so, what would be the best approach?

like image 963
Jon Tackabury Avatar asked Dec 05 '08 16:12

Jon Tackabury


2 Answers

I just went through the System.Web.Caching.Cache in reflector. It seems like everything that involves the expiry date is marked as internal. The only place i found public access to it, was through the Cache.Add and Cache.Insert methods.

So it looks like you are out of luck, unless you want to go through reflection, which I wouldn't recommend unless you really really need that date.

But if you wish to do it anyway, then here is some code that would do the trick:

private DateTime GetCacheUtcExpiryDateTime(string cacheKey)
{
    object cacheEntry = Cache.GetType().GetMethod("Get", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(Cache, new object[] { cacheKey, 1 });
    PropertyInfo utcExpiresProperty = cacheEntry.GetType().GetProperty("UtcExpires", BindingFlags.NonPublic | BindingFlags.Instance);
    DateTime utcExpiresValue = (DateTime)utcExpiresProperty.GetValue(cacheEntry, null);

    return utcExpiresValue;
}

Since .NET 4.5 the internal public getter of the HttpRuntime.Cache was replaced with a static variant and thus you will need to invoke/get the static variant:

object cacheEntry = Cache.GetType().GetMethod("Get").Invoke(null, new object[] { cacheKey, 1 });
like image 89
Tom Jelen Avatar answered Sep 29 '22 11:09

Tom Jelen


As suggested by someone in comments that the accepted answer does not work in .NET 4.7

I had a lot of trouble trying to figure out what changes needs to be done to make it work in .NET 4.7

Here's my code for people using .NET 4.7

private DateTime GetCacheUtcExpiryDateTime(string cacheKey)
{
    var aspnetcachestoreprovider = System.Web.HttpRuntime.Cache.GetType().GetProperty("InternalCache", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(System.Web.HttpRuntime.Cache, null);
    var intenralcachestore = aspnetcachestoreprovider.GetType().GetField("_cacheInternal", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(aspnetcachestoreprovider);
    Type TEnumCacheGetOptions = System.Web.HttpRuntime.Cache.GetType().Assembly.GetTypes().Where(d => d.Name == "CacheGetOptions").FirstOrDefault();
    object cacheEntry = intenralcachestore.GetType().GetMethod("DoGet", BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Any, new[] { typeof(bool), typeof(string), TEnumCacheGetOptions }, null).Invoke(intenralcachestore, new Object[] { true, cacheKey, 1 }); ;
    PropertyInfo utcExpiresProperty = cacheEntry.GetType().GetProperty("UtcExpires", BindingFlags.NonPublic | BindingFlags.Instance);
    DateTime utcExpiresValue = (DateTime)utcExpiresProperty.GetValue(cacheEntry, null);

    return utcExpiresValue;
}

And for those who wants the code to function in multiple different environments (sandbox using .NET 4.5 and production using .NET 4.7), here's some patch work:

private DateTime GetCacheUtcExpiryDateTime(string cacheKey)
{
    MethodInfo GetCacheEntryMethod = null;
    Object CacheStore = null;
    bool GetterFound = true;

    GetCacheEntryMethod = System.Web.HttpRuntime.Cache.GetType().GetMethod("Get", BindingFlags.Instance | BindingFlags.NonPublic);
    if (GetCacheEntryMethod != null)
    {
        GetterFound = true;
        CacheStore = System.Web.HttpRuntime.Cache;
    }
    else
    {
        var aspnetcachestoreprovider = System.Web.HttpRuntime.Cache.GetType().GetProperty("InternalCache", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(System.Web.HttpRuntime.Cache, null);
        var intenralcachestore = aspnetcachestoreprovider.GetType().GetField("_cacheInternal", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(aspnetcachestoreprovider);
        Type TEnumCacheGetOptions = System.Web.HttpRuntime.Cache.GetType().Assembly.GetTypes().Where(d => d.Name == "CacheGetOptions").FirstOrDefault();
        GetCacheEntryMethod = intenralcachestore.GetType().GetMethod("DoGet", BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Any, new[] { typeof(bool), typeof(string), TEnumCacheGetOptions }, null);
        GetterFound = false;
        CacheStore = intenralcachestore;
    }

    dynamic cacheEntry;
    if (GetterFound)
        cacheEntry = GetCacheEntryMethod.Invoke(CacheStore, new Object[] { cacheKey, 1 });
    else
        cacheEntry = GetCacheEntryMethod.Invoke(CacheStore, new Object[] { true, cacheKey, 1 });

    PropertyInfo utcExpiresProperty = cacheEntry.GetType().GetProperty("UtcExpires", BindingFlags.NonPublic | BindingFlags.Instance);
    DateTime utcExpiresValue = (DateTime)utcExpiresProperty.GetValue(cacheEntry, null);

    return utcExpiresValue;
}
like image 33
Sahil Shah Avatar answered Sep 29 '22 13:09

Sahil Shah