It turns out that it’s hard to implement caching in class libraries in .NET. The enterprise libraries have a Caching Application Block, but this is nice and light-weight, and it works nicely as a standalone, which the Caching Application Block won’t do for you because it requires a config file. ASP.NET has great support for Web caching in System.Web.Caching, and a few examples on the net actually suggest referencing that assembly in your class libraries or Win Forms apps, but that seems kind of… breaky… so here’s a simple custom cache implementation in C# that handles expiration. It’s not quite as nice as System.Web.Caching, but if you don’t like it, don’t use it.
I use this in a COM visible class library that gets used by a Classic ASP site. Works great.
CacheFactory class
public class CacheFactory
{
private Hashtable _data;
public CacheFactory()
{
_data = new Hashtable();
}
#region properties
public object this[string key]
{
get
{
object rtn = null;
RemoveExpiredItems();
CacheItem item = (CacheItem)_data[key];
if (item != null)
{
rtn = item.Data;
}
return rtn;
}
}
public int Count
{
get
{
RemoveExpiredItems();
return _data.Count;
}
}
public ICollection Keys
{
get
{
RemoveExpiredItems();
return _data.Keys;
}
}
#endregion
public void Add(string key, object data)
{
Add(key, data, 0);
}
public void Add(string key, object data, double minutes)
{
DateTime expiresAt;
if (minutes > 0)
expiresAt = DateTime.Now.AddMinutes(minutes);
else
expiresAt = DateTime.MinValue;
_data[key] = new CacheItem(key, data, expiresAt);
}
public void Remove(string key)
{
CacheItem item = (CacheItem)_data[key];
if (item != null)
_data.Remove(key);
}
public void Clear()
{
_data.Clear();
}
public DateTime ExpiresAt(string key)
{
DateTime rtn = DateTime.MinValue;
CacheItem item = (CacheItem)_data[key];
if (item != null)
{
rtn = item.ExpiresAt;
}
return rtn;
}
public string Name(string key)
{
RemoveExpiredItems();
string rtn = null;
CacheItem item = (CacheItem)_data[key];
if (item != null)
{
rtn = item.Name;
}
return rtn;
}
public CacheItem GetCacheItem(string key)
{
RemoveExpiredItems();
CacheItem item = (CacheItem)_data[key];
return item;
}
public bool IsExpired(string key)
{
bool rtn = false;
CacheItem item = (CacheItem)_data[key];
if (item.Expires && DateTime.Now > item.ExpiresAt)
{
rtn = true;
}
return rtn;
}
protected void RemoveExpiredItems()
{
CacheItem item;
DateTime expiresAt = DateTime.MaxValue;
StringCollection keys = new StringCollection();
foreach (string key in _data.Keys)
{
keys.Add(key);
}
foreach (string key in keys)
{
item = (CacheItem)_data[key];
if (item == null || (item.Expires && DateTime.Now > item.ExpiresAt))
_data.Remove(key);
}
}
}
CacheItem class
public class CacheItem
{
private object _data;
private DateTime _expiresAt;
private string _name;
public CacheItem(string name, object data, DateTime expiresAt)
{
_name = name;
_data = data;
_expiresAt = expiresAt;
}
public object Data
{
get
{
return _data;
}
}
public DateTime ExpiresAt
{
get
{
return _expiresAt;
}
}
public string Name
{
get
{
return _name;
}
}
public bool Expires
{
get
{
return (ExpiresAt != DateTime.MinValue);
}
}
}
References:
http://authors.aspalliance.com/aldotnet/