\$\begingroup\$
\$\endgroup\$
2
I'm willing to simplify the use of the ASP.NET cache.
I wrote this helper class:
public static class CacheHelper
{
public static T GetCached<T>(string key, Func<T> initializer, DateTime absoluteExpiration)
{
return GetCached(key, initializer, Cache.NoSlidingExpiration, absoluteExpiration);
}
public static T GetCached<T>(string key, Func<T> initializer, TimeSpan slidingExpiration)
{
return GetCached(key, initializer, slidingExpiration, Cache.NoAbsoluteExpiration);
}
public static T GetCached<T>(string key, Func<T> initializer, TimeSpan slidingExpiration, DateTime absoluteExpiration)
{
var httpContext = HttpContext.Current;
if (httpContext != null)
{
var obj = httpContext.Cache[key];
if (obj == null)
{
obj = initializer();
httpContext.Cache.Add(key, obj, null, absoluteExpiration, slidingExpiration, System.Web.Caching.CacheItemPriority.Default, null);
}
return (T)obj;
}
else
{
return initializer(); // no available cache
}
}
}
The idea is to let the developer write its method as usual, but wrapping it like this:
public MyClass GetSomeCachedData(){
return CacheHelper.GetCached(
"GetSomeCachedData, () =>
{
return ComputeExpensiveResult();
}
}, TimeSpan.FromMinutes(1), Cache.NoAbsoluteExpiration);
}
Do you see any issues? Can it be improved?
(I'm sticking to .NET 3.5)
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked May 7, 2013 at 16:10
1 Answer 1
\$\begingroup\$
\$\endgroup\$
2
Several suggestions:
- You could use MemoryCache class as of .NET 4, which would free you from
System.Web
assembly. - You should use lock in order to put the value to cache.
- You should take care of value types objects
So, here is the code:
public static T GetCached<T>(string key, Func<T> initializer, TimeSpan slidingExpiration, DateTime absoluteExpiration)
{
var httpContext = HttpContext.Current;
if (httpContext != null)
{
key = string.Intern(key);
lock(key) // locking on interned key
{
var obj = httpContext.Cache[key];
if (obj == null)
{
obj = initializer();
httpContext.Cache.Add(key, obj, null, absoluteExpiration, slidingExpiration, System.Web.Caching.CacheItemPriority.Default, null);
}
// taking care of value types
if (obj == null && (typeof (T)).IsValueType)
{
return default(T);
}
return (T)obj;
}
}
else
{
return initializer(); // no available cache
}
}
-
\$\begingroup\$ as I said, I'm sticked to the version 3.5 of the framework. That said, I think your lock is useless as the key is a string, and make the lock useless as the instance of the string will always be different, isn't it? \$\endgroup\$Steve B– Steve B2013年05月21日 15:59:28 +00:00Commented May 21, 2013 at 15:59
-
\$\begingroup\$ Every time the method would called with same key value,
string.Intern(key)
would return reference to same string, so lock should work as needed. \$\endgroup\$v0id– v0id2013年05月21日 21:16:40 +00:00Commented May 21, 2013 at 21:16
lang-cs
() => ComputeExpensiveResult()
, or even justComputeExpensiveResult
. Also,GetSomeCachedData()
should probably be a property. \$\endgroup\$