Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Linq;
- using System.Runtime.Caching;
- using System.Runtime.Serialization;
- using System.Runtime.Serialization.Formatters.Binary;
- using System.Threading;
- namespace Common.Caching
- {
- /// <summary>Uses <see cref="System.Runtime.Caching.MemoryCache"/> cache. Used on local client or server</summary>
- public class FileObjectCache : ObjectCache
- {
- #region static & const
- const string File_Extention = ".xml";
- const string Internal_Key_Prefix = "FileObjectCache_";
- static readonly FileObjectCache _default;
- public static FileObjectCache Default
- {
- get { return _default; }
- }
- static FileObjectCache()
- {
- _default = new FileObjectCache();
- }
- #endregion
- string _cacheName;
- long _memoryCount;
- public string CacheDirectory { get; private set; }
- public FileObjectCache() : this(null, null) { }
- public FileObjectCache(string cacheName) : this(cacheName, null) { }
- public FileObjectCache(string cacheName, string directory)
- {
- _cacheName = cacheName;
- this.CacheDirectory = directory;
- if (string.IsNullOrWhiteSpace(this.CacheDirectory))
- this.CacheDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "_FileCache");
- if (!string.IsNullOrWhiteSpace(_cacheName))
- this.CacheDirectory = Path.Combine(this.CacheDirectory, _cacheName);
- EnsureDestinationDirectory(this.CacheDirectory);
- }
- MemoryCache MemCache
- {
- get { return MemoryCache.Default; }
- }
- string GetInternalCacheKey(string key, string regionName = null)
- {
- return string.Format("{0}_{1}", Internal_Key_Prefix, key);
- }
- string GetCacheFile(string key, string regionName)
- {
- //if we want to store each cache item in a separate directory
- //string dirpath = GetCacheItemDirectory(key, regionName);
- //EnsureDestinationDirectory(dirpath);
- string fname = string.Format("{0}{1}", key.GetHashCode(), File_Extention);
- string fpath = Path.Combine(this.CacheDirectory, fname);
- return fpath;
- }
- string GetCacheItemDirectory(string key, string regionName)
- {
- string dirpath = Path.Combine(this.CacheDirectory, string.Format("{0}", key.GetHashCode()));
- return dirpath;
- }
- FileCacheItem ReadFileCacheItem(string fpath)
- {
- try
- {
- var citem = SerializeFromBytes<FileCacheItem>(File.ReadAllBytes(fpath));
- return citem;
- }
- catch (Exception error)
- {
- Debug.WriteLine(string.Format("FileObjectCache: There was an error reading the file '{0}'; Error: {1}", fpath, error.Message));
- return null;
- }
- }
- static byte[] SerializeToBytes(object source)
- {
- if (!source.GetType().IsSerializable)
- throw new ArgumentException("The type must be serializable.", "source");
- IFormatter formatter = new BinaryFormatter();
- using (var stream = new MemoryStream())
- {
- formatter.Serialize(stream, source);
- stream.Seek(0, SeekOrigin.Begin);
- return stream.ToArray();
- }
- }
- static T SerializeFromBytes<T>(byte[] buffer)
- {
- if (!typeof(T).IsSerializable)
- throw new ArgumentException("The type must be serializable.", "T");
- IFormatter formatter = new BinaryFormatter();
- using (var stream = new MemoryStream(buffer))
- {
- if (stream.Position > 0)
- stream.Seek(0, SeekOrigin.Begin);
- return (T)formatter.Deserialize(stream);
- }
- }
- static void EnsureDestinationDirectory(string path)
- {
- string dirpath = path;
- if (Path.HasExtension(path))
- dirpath = Path.GetDirectoryName(path);
- if (!Directory.Exists(dirpath))
- Directory.CreateDirectory(dirpath);
- }
- static bool DeleteSafe(string filepath, out Exception error)
- {
- error = null;
- try
- {
- if (!File.Exists(filepath))
- return true;
- File.Delete(filepath);
- return true;
- }
- catch (Exception deleteError)
- {
- error = deleteError;
- try
- {
- File.SetAttributes(filepath, FileAttributes.Normal);
- File.Delete(filepath);
- error = null;
- return true;
- }
- catch (Exception atterror)
- {
- error = atterror;
- return false;
- }
- }
- }
- public override object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = null)
- {
- var cacheData = Get(key, regionName);
- if (cacheData == null)
- Set(key, value, policy, regionName);
- return cacheData;
- }
- public override CacheItem AddOrGetExisting(CacheItem value, CacheItemPolicy policy)
- {
- var citem = GetCacheItem(value.Key, value.RegionName);
- if (citem == null)
- Set(citem, policy);
- return citem;
- }
- public override object AddOrGetExisting(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
- {
- var cacheData = Get(key, regionName);
- if (cacheData == null)
- Set(key, value, absoluteExpiration, regionName);
- return cacheData;
- }
- public override bool Contains(string key, string regionName = null)
- {
- return Get(key, regionName) != null;
- }
- public override CacheEntryChangeMonitor CreateCacheEntryChangeMonitor(System.Collections.Generic.IEnumerable<string> keys, string regionName = null)
- {
- return null;
- }
- public override DefaultCacheCapabilities DefaultCacheCapabilities
- {
- get
- {
- return DefaultCacheCapabilities.OutOfProcessProvider
- | DefaultCacheCapabilities.AbsoluteExpirations;
- }
- }
- public override object Get(string key, string regionName = null)
- {
- string internalKey = GetInternalCacheKey(key);
- FileCacheItem fitem = MemCache.Get(internalKey, regionName) as FileCacheItem;
- if (fitem == null)
- {
- //check to see if we have the data on file
- string filepath = GetCacheFile(key, regionName);
- if (File.Exists(filepath))
- {
- fitem = ReadFileCacheItem(filepath);
- if (fitem != null && fitem.Value != null)
- {
- //check for expiration
- if (DateTimeOffset.Now >= fitem.AbsoluteExpiration)
- {
- Remove(key, regionName);
- fitem = null;
- }
- else
- {
- //add to local memory
- CacheItemPolicy policy = new CacheItemPolicy();
- policy.AbsoluteExpiration = fitem.AbsoluteExpiration;
- MemCache.Set(internalKey, fitem, policy, regionName);
- }
- }
- }
- }
- if (fitem != null && fitem.Value != null)
- return fitem.Value.GetValue();
- else
- return null;
- }
- public override CacheItem GetCacheItem(string key, string regionName = null)
- {
- string internalKey = GetInternalCacheKey(key);
- var citem = MemCache.GetCacheItem(internalKey, regionName);
- if (citem == null)
- {
- citem = MemCache.GetCacheItem(key, regionName);
- if (citem == null)
- {
- var value = Get(key, regionName);
- if (value != null)
- citem = new CacheItem(key, value, regionName);
- }
- }
- return citem;
- }
- public override long GetCount(string regionName = null)
- {
- long mcount = Interlocked.Read(ref _memoryCount);
- if (mcount <= 0 && Directory.Exists(CacheDirectory))
- {
- long fcount = Directory.GetFiles(CacheDirectory, string.Format("*{0}", File_Extention)).LongLength;
- if (fcount != mcount)
- Interlocked.Exchange(ref _memoryCount, fcount);
- }
- return mcount;
- }
- protected override System.Collections.Generic.IEnumerator<KeyValuePair<string, object>> GetEnumerator()
- {
- long mcount = Interlocked.Read(ref _memoryCount);
- if (mcount <= 0 && Directory.Exists(CacheDirectory))
- {
- //iterate though the cache directory
- foreach (var fpath in Directory.EnumerateFiles(CacheDirectory, string.Format("*{0}", File_Extention)))
- {
- var citem = ReadFileCacheItem(fpath);
- if (citem == null)
- continue;
- string key = citem.Key;
- object value = citem.Value.GetValue();
- var internalKey = GetInternalCacheKey(key);
- yield return new KeyValuePair<string, object>(key, value);
- }
- }
- else
- {
- foreach (var citem in MemCache)
- {
- if (citem.Key.StartsWith(Internal_Key_Prefix))
- yield return citem;
- }
- }
- }
- public override System.Collections.Generic.IDictionary<string, object> GetValues(System.Collections.Generic.IEnumerable<string> keys, string regionName = null)
- {
- Dictionary<string, object> dict = new Dictionary<string, object>(keys.Count());
- foreach (string key in keys)
- dict[key] = Get(key, regionName);
- return dict;
- }
- public override string Name
- {
- get { return _cacheName; }
- }
- public override object Remove(string key, string regionName = null)
- {
- string internalKey = GetInternalCacheKey(key);
- object cacheData = null;
- if (MemCache.Contains(internalKey, regionName))
- {
- var fitem = MemCache.Remove(internalKey, regionName) as FileCacheItem;
- if (fitem != null)
- cacheData = fitem.Value.GetValue();
- Interlocked.Decrement(ref _memoryCount);
- }
- //check to see if we have the data on file
- string filepath = GetCacheFile(key, regionName);
- if (File.Exists(filepath))
- {
- //delete if exists
- Exception deleteError = null;
- if (!DeleteSafe(filepath, out deleteError))
- throw deleteError;
- }
- return cacheData;
- }
- public override void Set(string key, object value, CacheItemPolicy policy, string regionName = null)
- {
- SetInternal(new FileCacheItem(key, value, regionName), policy, regionName);
- }
- public override void Set(CacheItem item, CacheItemPolicy policy)
- {
- SetInternal(new FileCacheItem(item), policy);
- }
- public override void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
- {
- CacheItemPolicy policy = new CacheItemPolicy();
- policy.AbsoluteExpiration = absoluteExpiration;
- SetInternal(new FileCacheItem(key, value, regionName), policy, regionName);
- }
- void SetInternal(FileCacheItem fitem, CacheItemPolicy policy, string regionName = null)
- {
- string key = fitem.Key;
- object value = fitem.Value;
- string internalKey = GetInternalCacheKey(key);
- //remove any existing items
- this.Remove(key, regionName);
- fitem.AbsoluteExpiration = policy.AbsoluteExpiration;
- //save to file
- string filepath = GetCacheFile(key, regionName);
- byte[] contents = SerializeToBytes(fitem);
- File.WriteAllBytes(filepath, contents);
- //add to memory
- if (fitem.OriginalCacheItem == null)
- MemCache.Set(internalKey, fitem, policy, regionName);
- else
- {
- MemCache.Set(fitem.OriginalCacheItem, policy);
- }
- Interlocked.Increment(ref _memoryCount);
- }
- public override object this[string key]
- {
- get { return Get(key); }
- set { Set(key, value, DateTimeOffset.MaxValue); }
- }
- }
- /// <summary>
- /// Represents an individual cache entry in the cache. Same as <see cref="CacheItem"/>, but marked as serializable
- /// </summary>
- [Serializable]
- public class FileCacheItem
- {
- [NonSerialized]
- CacheItem _originalCacheItem;
- /// <summary>
- /// Initializes a new <see cref="T:System.Runtime.Caching.CacheItem"/> instance using the specified key of a cache entry.
- /// </summary>
- public FileCacheItem() : this(null, null) { }
- /// <summary>
- /// Initializes a new <see cref="T:System.Runtime.Caching.CacheItem"/> instance using the specified key of a cache entry.
- /// </summary>
- public FileCacheItem(CacheItem cacheItem)
- : this(cacheItem.Key, cacheItem.Value, cacheItem.RegionName)
- {
- _originalCacheItem = cacheItem;
- }
- /// <summary>
- /// Initializes a new <see cref="T:System.Runtime.Caching.CacheItem"/> instance using the specified key of a cache entry.
- /// </summary>
- /// <param name="key">A unique identifier for a <see cref="T:System.Runtime.Caching.CacheItem"/> entry. </param>
- public FileCacheItem(string key) : this(key, null) { }
- /// <summary>
- /// Initializes a new <see cref="T:System.Runtime.Caching.CacheItem"/> instance using the specified key and a value of the cache entry.
- /// </summary>
- /// <param name="key">A unique identifier for a <see cref="T:System.Runtime.Caching.CacheItem"/> entry.</param><param name="value">The data for a <see cref="T:System.Runtime.Caching.CacheItem"/> entry.</param>
- public FileCacheItem(string key, object value) : this(key, value, null) { }
- /// <summary>
- /// Initializes a new <see cref="T:System.Runtime.Caching.CacheItem"/> instance using the specified key, value, and region of the cache entry.
- /// </summary>
- /// <param name="key">A unique identifier for a <see cref="T:System.Runtime.Caching.CacheItem"/> entry.</param><param name="value">The data for a <see cref="T:System.Runtime.Caching.CacheItem"/> entry.</param><param name="regionName">The name of a region in the cache that will contain the <see cref="T:System.Runtime.Caching.CacheItem"/> entry.</param>
- public FileCacheItem(string key, object value, string regionName)
- {
- this.Key = key;
- this.Value = new SerializableObjectWrapper(value);
- this.RegionName = regionName;
- this.AbsoluteExpiration = DateTimeOffset.MaxValue;
- }
- public CacheItem OriginalCacheItem
- {
- get { return _originalCacheItem; }
- set { _originalCacheItem = value; }
- }
- /// <summary>
- /// Gets or sets a unique identifier for a <see cref="T:System.Runtime.Caching.CacheItem"/> instance.
- /// </summary>
- ///
- /// <returns>
- /// The identifier for a <see cref="T:System.Runtime.Caching.CacheItem"/> instance.
- /// </returns>
- public string Key { get; set; }
- /// <summary>
- /// Gets or sets the data for a <see cref="T:System.Runtime.Caching.CacheItem"/> instance.
- /// </summary>
- ///
- /// <returns>
- /// The data for a <see cref="T:System.Runtime.Caching.CacheItem"/> instance. The default is null.
- /// </returns>
- public SerializableObjectWrapper Value { get; set; }
- /// <summary>
- /// Gets or sets the name of a region in the cache that contains a <see cref="T:System.Runtime.Caching.CacheItem"/> entry.
- /// </summary>
- ///
- /// <returns>
- /// The name of a region in a cache. The default is null.
- /// </returns>
- public string RegionName { get; set; }
- /// <summary>
- /// Gets or sets a value that indicates whether a cache entry should be evicted after a specified duration.
- /// </summary>
- public DateTimeOffset AbsoluteExpiration { get; set; }
- }
- /// <summary>Wraps objects that aren't marked as serializable and uses Xml serialization to serialize and deserialize them</summary>
- [Serializable]
- public class SerializableObjectWrapper : ISerializable
- {
- [NonSerialized]
- object obj;
- string objxml;
- Type objType;
- public Type ObjectType
- {
- get { return objType; }
- }
- protected SerializableObjectWrapper(SerializationInfo info, StreamingContext context)
- {
- objxml = (string)info.GetValue("objxml", typeof(string));
- objType = (Type)info.GetValue("objType", typeof(Type));
- }
- public SerializableObjectWrapper(object core)
- {
- this.obj = core;
- if (core != null)
- this.objType = core.GetType();
- }
- public object GetValue()
- {
- if (obj == null)
- {
- if (string.IsNullOrWhiteSpace(objxml))
- return null;
- Type obtype = this.ObjectType;
- if (obtype == null)
- obtype = typeof(object);
- obj = Deserialize(objxml, obtype);
- }
- return obj;
- }
- public void GetObjectData(SerializationInfo info, StreamingContext context)
- {
- info.AddValue("objxml", Serialize(obj));
- info.AddValue("objType", objType);
- }
- static string Serialize(object xmlObject, bool encodeInBase64 = false)
- {
- using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream())
- {
- System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(xmlObject.GetType());
- System.Xml.Serialization.XmlSerializerNamespaces xmlNamespace = new System.Xml.Serialization.XmlSerializerNamespaces();
- xmlNamespace.Add(string.Empty, string.Empty);
- xs.Serialize(memoryStream, xmlObject, xmlNamespace);
- System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
- if (encodeInBase64)
- return Convert.ToBase64String(System.Text.ASCIIEncoding.Unicode.GetBytes(encoding.GetString(memoryStream.ToArray())));
- else
- return encoding.GetString(memoryStream.ToArray());
- }
- }
- static object Deserialize(string xml, Type objtype)
- {
- bool decodeInBase64 = false;
- string data = xml;
- if (decodeInBase64)
- data = System.Text.ASCIIEncoding.Unicode.GetString(Convert.FromBase64String(xml));
- System.Xml.Serialization.XmlSerializer xs = System.Xml.Serialization.XmlSerializer.FromTypes(new Type[] { objtype })[0];
- System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
- using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(encoding.GetBytes(data)))
- {
- System.Xml.XmlTextWriter xmlTextWriter = new System.Xml.XmlTextWriter(memoryStream, System.Text.Encoding.UTF8);
- return xs.Deserialize(memoryStream);
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment