I’ve seen some people talking about Silverlight Caching on the Silverlight forum. And because there’s no solution that can be compared to for example the ASP.NET solution for Caching. Of course it’s not that difficult to keep some data in a simple reference, just a variable, maybe on global maybe on class level. But yes, if you want a little bit more advanced Cache which supports the expiring of data you’ll need something different.
For the general purpose of caching data which can expire after a certain timespan I wrote this solution that can be used in Silverlight 2 and 3. You can view the whole code at the end of this article.
Adding and getting data from Cache
I wanted a solution that could work with general objects the way I work in this example.
Cache.Current.Add("Testkey", 10, TimeSpan.FromMinutes(2)); object cacheData = Cache.Current.Get("Testkey"); if(cacheData!=null) { int cacheDataTyped = (int) cacheData; }
In those situations you will have to cast the data to the required Type or Structure. This works fine, we’ve done this before while accessing the ASP.NET Cache. But sometimes you’ll want to have it typed immediately. So I want to be able to use this as well.
User user = GetUser(); Cache.Current.Add("Testkeytyped", user, TimeSpan.FromMinutes(4)); User userFromCache = Cache.Current.Get<User>("Testkeytyped");
So I had to add a Generic function Get and a none Generic function Get. I did this, and the code above works fine indeed.
But what about expiring data?
To expire data I wanted to provide a TimeSpan while adding the item to the cache. The first solution I thought of was to remove items upon get if it’s no longer valid. But in the end I thought what if the amount of data is large, in those cases you want it removed as soon as it is expired. So I found a different solution. By making use of the Timer class in Silverlight. I want the timer to tick every minute, and on tick I want it to clean the cache. So the current solutions cleans up items in the cache every minute. And upon getting of items it will check if the item is still valid or not.
Please feel free to use this is solution. It’s not thread-safe, but you can add thread-safe support yourself if you want to.
/// <summary> /// Class supports in memory cache for Silverlight applications. Silverlight 2 and 3 are supported. /// Each minute the cache items are iterated for validility, invalid cache items are removed. /// </summary> public class Cache : IDisposable { public static Cache Current = new Cache(); private readonly IDictionary<string, CacheItem> _cacheItems = new Dictionary<string, CacheItem>(); private readonly TimeSpan _period = TimeSpan.FromMinutes(1); private readonly TimeSpan _startTimeSpan = TimeSpan.Zero; private readonly TimeSpan _stopTimeSpan = TimeSpan.FromMilliseconds(-1); private readonly Timer _timer; private TimerState _state = TimerState.Stopped; private Cache() { _timer = new Timer(CleanUpItems, this, _stopTimeSpan, _period); } /// <summary> /// All the CacheItems are in a Dictionary /// </summary> public IDictionary<string, CacheItem> CacheItems { get { return _cacheItems; } } /// <summary> /// Get full CacheItem based on key. /// </summary> /// <param name="key">The key for which a CacheItem is stored.</param> /// <returns>The CacheItem stored for the given key, if it is still valid. Otherwise null.</returns> public CacheItem this[string key] { get { if (CacheItems.ContainsKey(key)) { CacheItem ci = CacheItems[key]; if (ci.IsValid()) return CacheItems[key]; } return null; } set { CacheItems[key] = value; } } #region IDisposable Members public void Dispose() { _timer.Dispose(); } #endregion /// <summary> /// Get data typed directly for given key. /// </summary> /// <typeparam name="T">The Type for which the data is set. If the type is wrong null will be returned.</typeparam> /// <param name="key">The key for which a CacheItem is stored.</param> /// <returns>The data typed for the given key, if it is still valid. Otherwise null.</returns> public T Get<T>(string key) where T : class { CacheItem item = this[key]; if (item != null) return item.GetData<T>(); return null; } /// <summary> /// Get data untyped directly for given key. /// </summary> /// <param name="key">The key for which a CacheItem is stored.</param> /// <returns>The data untyped for the given key, if it is still valid. Otherwise null.</returns> public object Get(string key) { CacheItem item = this[key]; if (item != null) return item.GetData(); return null; } private void StartTimer() { if (_state == TimerState.Stopped) { _timer.Change(_startTimeSpan, _period); _state = TimerState.Started; } } private void StopTimer() { if (_state == TimerState.Started) { _timer.Change(_stopTimeSpan, _period); _state = TimerState.Stopped; } } /// <summary> /// Clean up items that are not longer valid. /// </summary> /// <param name="state">Expect state to be the cache object.</param> private static void CleanUpItems(object state) { var cache = state as Cache; if (cache != null) { List<KeyValuePair<string, CacheItem>> itemsToRemove = cache.CacheItems.Where(i => !i.Value.IsValid()).ToList(); foreach (var item in itemsToRemove) { cache.CacheItems.Remove(item.Key); } if (cache.CacheItems.Count == 0) cache.StopTimer(); } } /// <summary> /// Add a new item to the cache. If the key is already used it will be overwritten. /// </summary> /// <param name="key">The key for which a CacheItem is stored.</param> /// <param name="value"></param> public void Add(string key, CacheItem value) { if (_cacheItems.ContainsKey(key)) _cacheItems.Remove(key); _cacheItems.Add(key, value); StartTimer(); } /// <summary> /// Add a new item to the cache. If the key is already used it will be overwritten. /// </summary> /// <param name="key">The key for which a CacheItem is stored.</param> /// <param name="data">The data to cache.</param> /// <param name="validDuration">The duration of the caching of the data.</param> public void Add(string key, object data, TimeSpan validDuration) { Add(key, new CacheItem(data, validDuration)); } /// <summary> /// Removes the item for the given key from the cache. /// </summary> /// <param name="key">The key for which a CacheItem is stored.</param> /// <returns></returns> public bool Remove(string key) { bool remove = _cacheItems.Remove(key); if (_cacheItems.Count == 0) StopTimer(); return remove; } #region Nested type: TimerState /// <summary> /// Used for determing TimerState /// </summary> private enum TimerState { Stopped, Started } #endregion }
/// <summary> /// Defines an item that's stored in the Cache. /// </summary> public class CacheItem { private readonly DateTime _creationDate = DateTime.Now; private readonly TimeSpan _validDuration; /// <summary> /// Constructs a cache item with for the data with a validity of validDuration. /// </summary> /// <param name="data">The data for the cache.</param> /// <param name="validDuration">The duration for the data being valid in the cache.</param> public CacheItem(object data, TimeSpan validDuration) { _validDuration = validDuration; Data = data; } /// <summary> /// The data in the Cache. /// </summary> public object Data { set; private get; } /// <summary> /// Gets the Data typed. /// </summary> /// <typeparam name="T">The Type for which the data is set. If the type is wrong null will be returned.</typeparam> /// <returns>The data typed.</returns> public T GetData<T>() where T : class { return Data as T; } /// <summary> /// Gets the Data untyped. /// </summary> /// <returns>The data untyped.</returns> public object GetData() { return Data; } /// <summary> /// Check if the Data is still valid. /// </summary> /// <returns>Valid if the validDuration hasn't passed.</returns> public bool IsValid() { return _creationDate.Add(_validDuration) > DateTime.Now; } }
Ps. This article is cross posted on: Mark Monster’s blog and Silverlight Help.
I did something similar with my project, but also had a commit to semi-permanent cache. In effect this serialized it to the Isolated Storage in Silverlight. I also changed the syntax around to use lambda expressions with fluent extensions.
P.S. Do you cross post your articles on DZone, DotNetKicks, DotNetShoutout or SilverlightCream?
Isolated Storage is interesting as well. But we always have to keep in mind it's got a quota.
I think using fluent languages really is a good addition.
And yes I'm cross posting, but only on: SilverlightCream and Silverlight-help.com
Multiple versions of the same article bug the heck out of me, especially when I find one thats on a really hard to read website. Do they pay for your articles?
Thanks
Ben
uggs outlet online ventura ca http://fortuneangel.com/
ugg outlet store shoes http://www.inflatablescompany.com/
ugg outlet store location http://www.iwillnotbesilent.com/brand/
us ugg boots outlet http://www.jubileegang.com/
ugg outlet online boots http://www.inflatablescompany.com/
Tiffany & co http://www.tiffanyandco.com.co
louis vuitton bag http://www.cheaplouisvuittonbagsonsale.net
wohenniubixo http://www.cafabirdclub.org/shop.asp?ie=tall+chestnut+ugg+boots.aspx
New Balance Shoes http://www.newbalanceblackfriday.com
new balance shop online http://www.shoppingnewbalancesoutletonline.com
new balance store http://www.newbalanceshoesoutletstores.com
new balance shoes http://www.newbalanceshoes574.com
I've bookmarked it for later!
new balance store locator http://www.newbalancestorelocator.com
And i'm glad reading your article. But should commentary on few normal issues, The web site taste is perfect, the articles is in point of fact excellent :
D. Excellent activity, cheers
web site (Eusebia)
Kate Spade Online Sale http://www.katespadehandbags.net
tiffany bracelet http://www.tiffanyjewelry.com.co
katespade.com http://www.katespadeoutletinc.com
web page - Francesco,
listen news on TV, thus I just use web for that purpose,
and get the hottest news.
webpage (Indira)
ray bans usa http://www.usaraybanssunglassesstore.com
ralph lauren sales online http://www.ralphlaurensaleonline-uk.com
coach factory http://www.coachfactoryoutletonlineshopping.com
coach purses http://www.coachpursesoutletonline2014.com
louisvuitton.com http://www.louisvuittonoutletsyear.com
coach on sale http://www.coachpursesonsale-wholesale.com
pink coach http://www.wholesalecheappinkcoachbackpacks.com
chanel bags http://www.chanelfactoryoutletstore.com.co
louboutins online http://www.wholesalechristianlouboutinonline.com
writing to improve my know-how.
website (Tilly)
And i am glad reading your article. But wanna remark on some general things, The site style is great, the articles is really excellent : D.
Good job, cheers
homepage (Chante)
to create a killer headline? I mean, I don't wish to tell you
how to run your blog, however suppose you added a headline that makes
people desire more? I mean In memory cache for
Silverlight 2 and 3 - Silverlight, WP7, .NET, C#, ASP.NET MVC is kinda plain. You
ought to glance at Yahoo's home page and watch how they create post
headlines to grab people to open the links.
You might add a related video or a related picture
or two to grab readers interested about everything've
written. Just my opinion, it would make your posts a little bit more interesting.
web page (Franchesca)
I put things off a lot and don't seem to get anything done.
web page (Heidi)
web page (Adam)
homepage; Oscar,
It's always useful to read articles from other writers and use a little
something from their websites.
at this webpage, thanks admin of this web site.
web site (Timothy)
my time here at web, however I know I am getting know-how everyday
by reading such good articles.
author.I will be sure to bookmark your blog and may come
back very soon. I want to encourage that you
continue your great work, have a nice day!
favorite justification appeared to be at the internet the easiest thing to remember of.
I say to you, I certainly get annoyed whilst other folks consider worries that they just
do not recognize about. You managed to hit the nail upon the top and
outlined out the entire thing without having side-effects , people could take a
signal. Will probably be again to get more. Thanks
website [Mira]
be updated daily. It carries fastidious stuff.
Jaimie
so I simply use web for that reason, and obtain the latest news.
Junko
I most certainly will highly recommend this website!
Louvenia