In every application you have some data that is more read-more,write-once or twice. For example you can have the list of Cities of a country,the list of Countries of the world or list of exchange currency. This data is modified rarely. Also,you can have data that is not very sensitive to be real-time,such as the list of invoices for the day.
In .NET 3.5 you have several options
1. ASP.NET caching – and implementing in other applications with HttpRuntime ( even if MS says “The Cache class is not intended for use outside of ASP.NET applications”)
2. Enterprise caching block : hard to configure
3. memcached,velocity,sharedcache and other third party providers – that comes with their options and configuration
In .NET 4.0 you have a new kid : objectcache and,more important,an implementation : MemoryCache
http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache%28v=VS.100%29.aspx
What is very good is that now you can cache in Memory what do you want – and apply easily to your Business Layer. More,the object is a singleton for the application – that is even better (see the test on the final of the post)
What it is missing is an easy implementation for List and an implementation to remove data after a defined time.
So I decided to do my implementation for that (ok,it is wrong to have both implementations in a single class – but you can separate easily )
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Caching;
namespace CachingData{
/// <summary>
/// List<int> i = new List<int>() { 1,10,100 };
//CacheData_List<List<int>,int> data = new CacheData_List<List<int>,int>(2);
//data.Add(i);
//Assert.AreEqual(3,data.Items().Count,"must be 3");
//data = new CacheData_List<List<int>,int>();
//Assert.AreEqual(3,data.Items().Count,"must be 3");
//Assert.IsTrue(data.ContainsData,"must have data");
//Thread.Sleep(1000 * 3);
//Assert.IsFalse(data.ContainsData,"must not have data");
/// </summary>
/// <typeparam name="T">and generic ILIST </typeparam>
/// <typeparam name="U"></typeparam>
public class CacheData_List<T,U>
where T:class,IList<U>,new()
{
/// <summary>
/// use this for adding in cache
/// </summary>
public event EventHandler RemovedCacheItem;
private System.Timers.Timer timerEvent;
private MemoryCache buffer;
private int TimeToLiveSeconds;
private DateTimeOffset dto;
private string Key;
/// <summary>
/// default constructor - cache 600 seconds = 10 minutes
/// </summary>
public CacheData_List()
: this(600)
{
}
/// <summary>
/// constructor cache the mentioned TimeSeconds time
/// </summary>
/// <param name="TimeSeconds">value of time for cache</param>
public CacheData_List(int TimeSeconds)
{
TimeToLiveSeconds = TimeSeconds;
timerEvent=new System.Timers.Timer(TimeToLiveSeconds * 1000);
timerEvent.AutoReset = true;
timerEvent.Elapsed += new System.Timers.ElapsedEventHandler(timerEvent_Elapsed);
dto = new DateTimeOffset(DateTime.UtcNow.AddSeconds(TimeToLiveSeconds));
Key = typeof(T).ToString();
buffer = MemoryCache.Default;
}
void timerEvent_Elapsed(object sender,System.Timers.ElapsedEventArgs e)
{
if (RemovedCacheItem != null)
{
RemovedCacheItem(this,EventArgs.Empty);
}
}
/// <summary>
/// remove item from cache
/// </summary>
public void Remove()
{
if (buffer.Contains(Key))
{
buffer.Remove(Key);
}
dto=new DateTimeOffset(DateTime.UtcNow.AddSeconds(TimeToLiveSeconds));
}
/// <summary>
/// add multiple items to cache
/// </summary>
/// <param name="items">items to add to the cache</param>
public void Add(T items)
{
if (buffer.Contains(Key))
{
T data = Items();
foreach (var t in data)
{
items.Add(t);
}
buffer.Remove(Key);
}
buffer.Add(Key,items,dto);
}
/// <summary>
/// add a item to the IList of the cache
/// </summary>
/// <param name="item">an item to add</param>
public void AddItem(U item)
{
T data=new T();
if (buffer.Contains(Key))
{
data = buffer.Get(Key) as T;
buffer.Remove(Key);
}
data.Add(item);
buffer.Add(Key,data,dto);
}
/// <summary>
/// usefull if you do not intercept the removed event
/// </summary>
public bool ContainsData
{
get
{
return buffer.Contains(Key);
}
}
/// <summary>
/// retrieve items
/// </summary>
/// <returns></returns>
public T Items()
{
if (!buffer.Contains(Key))
return null;
return buffer.Get(Key) as T;
}
}
}
Please note that the test for usage is in the summary :
</pre>
List i = new List() { 1,10,100 };
CacheData_List <List<int>,int> data = new CacheData_List<List<int>,int>(2);
data.Add(i);
Assert.AreEqual(3,data.Items().Count,"must be 3");
data = new CacheData_List<List<int>,int>();
Assert.AreEqual(3,data.Items().Count,"must be 3");
Assert.IsTrue(data.ContainsData,"must have data");
Thread.Sleep(1000 * 3);
Assert.IsFalse(data.ContainsData,"must not have data");
You can download the file from
http://msprogrammer.serviciipeweb.ro/wp-content/uploads/2010/05/CachingData.zip
(Last Note : for synchonization maybe it was better to lock on readerwriterlockslim
Leave a Reply