using System; using System.Collections.Generic; using System.IO; using System.IO.IsolatedStorage; using System.Linq; using System.Runtime.Serialization; namespace Phone7.Fx.Preview { /// /// /// public class Cache { public static readonly DateTime NoAbsoluteExpiration = DateTime.MaxValue; public static readonly TimeSpan NoSlidingExpiration = TimeSpan.Zero; readonly IsolatedStorageFile _myStore = IsolatedStorageFile.GetUserStoreForApplication(); private object _sync = new object(); private static Cache _current; /// /// Gets the current instance of the cache /// /// The current. public static Cache Current { get { return _current ?? (_current = new Cache()); } } /// /// Adds the specified key. /// /// The key. /// The value. /// The absolute expiration. /// The sliding expiration. public void Add(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration) { lock (_sync) { if (Contains(key)) Remove(key); if (absoluteExpiration == NoAbsoluteExpiration) Add(key, DateTime.UtcNow + slidingExpiration, value); if (slidingExpiration == NoSlidingExpiration) Add(key, absoluteExpiration, value); } } /// /// Adds the specified key. /// /// The key. /// The expiration date. /// The value. private void Add(string key, DateTime expirationDate, object value) { lock (_sync) { if (!_myStore.DirectoryExists(key)) _myStore.CreateDirectory(key); else { string currentFile = GetFileNames(key).FirstOrDefault(); if (currentFile != null) _myStore.DeleteFile(string.Format("{0}\\{1}", key, currentFile)); _myStore.DeleteDirectory(key); _myStore.CreateDirectory(key); } string fileName = string.Format("{0}\\{1}.cache", key, expirationDate.ToFileTimeUtc()); if (_myStore.FileExists(fileName)) _myStore.DeleteFile(fileName); NormalWrite(fileName, value); } } /// /// Determines whether the cache contains the specified key. /// /// The key. /// /// true if [contains] [the specified key]; otherwise, false. /// public bool Contains(string key) { lock (_sync) { if (_myStore.DirectoryExists(key) && GetFileNames(key).Any()) { string currentFile = GetFileNames(key).FirstOrDefault(); if (currentFile != null) { var expirationDate = DateTime.FromFileTimeUtc(long.Parse(Path.GetFileNameWithoutExtension(currentFile))); if (expirationDate >= DateTime.UtcNow) return true; } } return false; } } /// /// Removes the specified key. /// /// The key. public void Remove(string key) { lock (_sync) { if (!Contains(key)) throw new AccessViolationException("The key does not exist in the cache"); string currentFile = GetFileNames(key).FirstOrDefault(); if (currentFile != null) _myStore.DeleteFile(string.Format("{0}\\{1}", key, currentFile)); _myStore.DeleteDirectory(key); } } /// /// Gets the file names. /// /// The key. /// private IEnumerable GetFileNames(string key) { return _myStore.GetFileNames(string.Format("{0}\\*.cache", key)); } /// /// Gets the specified key. /// /// /// The key. /// public T Get(string key) { lock (_sync) { string currentFile = GetFileNames(key).FirstOrDefault(); if (currentFile != null) { var expirationDate = DateTime.FromFileTimeUtc(long.Parse(Path.GetFileNameWithoutExtension(currentFile))); if (expirationDate >= DateTime.UtcNow) { return NormalRead(string.Format(@"{0}\{1}", key, currentFile)); } Remove(key); } return default(T); } } #region Serialization private T NormalRead(string fileName) { using (var isolatedStorageFileStream = new IsolatedStorageFileStream(fileName, FileMode.Open, _myStore)) { DataContractSerializer s = new DataContractSerializer(typeof(T)); var value = s.ReadObject(isolatedStorageFileStream); isolatedStorageFileStream.Close(); return (T)value; } } private void NormalWrite(string fileName, object value) { using (var isolatedStorageFileStream = new IsolatedStorageFileStream(fileName, FileMode.OpenOrCreate, _myStore)) { DataContractSerializer s = new DataContractSerializer(value.GetType()); s.WriteObject(isolatedStorageFileStream, value); } } #endregion } }