using System; using System.Diagnostics; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Security.Cryptography; using System.Text; using System.Web.Caching; using MongoDB.Driver; using SN.Setting; namespace SN.Caching.OutputCaching { public class DocumentDatabaseOutputCacheProvider: OutputCacheProvider { readonly MongoCollection _cacheItems; public DocumentDatabaseOutputCacheProvider() { MongoServerSettings settings = new MongoServerSettings { Server = new MongoServerAddress(Settings.Instance.Get("Caching.OutputCache", "MongoDBName"), 27017) }; MongoServer server = new MongoServer(settings); MongoDatabase mongo = server.GetDatabase("OutputCacheDB"); _cacheItems = mongo.GetCollection("CacheItems"); } public override object Get(string key) { Debug.WriteLine(string.Format("Cache.Get({0})", key)); key = Md5(key); var query = MongoDB.Driver.Builders.Query.EQ("_id", key); var cacheItem = _cacheItems.FindOneAs(query); if (cacheItem != null) { if (cacheItem.Expiration.ToUniversalTime() <= DateTime.UtcNow) { _cacheItems.Remove(query); } else { return Deserialize(cacheItem.Item); } } return null; } public override object Add(string key, object entry, DateTime utcExpiry) { Debug.WriteLine("Cache.Add({0}, {1}, {2})", key, entry, utcExpiry); key = Md5(key); if (utcExpiry == DateTime.MaxValue) utcExpiry = DateTime.UtcNow.AddMinutes(5); var query = MongoDB.Driver.Builders.Query.EQ("_id", key); var cacheItem = _cacheItems.FindOneAs(query); if (cacheItem != null) { if (cacheItem.Expiration.ToUniversalTime() <= DateTime.UtcNow) { _cacheItems.Remove(query); } else { return Deserialize(cacheItem.Item); } } _cacheItems.Insert(new CacheItem { Id = key, Item = Serialize(entry), Expiration = utcExpiry }); return entry; } public override void Set(string key, object entry, DateTime utcExpiry) { Debug.WriteLine("Cache.Set({0}, {1}, {2})", key, entry, utcExpiry); key = Md5(key); var query = MongoDB.Driver.Builders.Query.EQ("_id", key); var cacheItem = _cacheItems.FindOneAs(query); if (cacheItem != null) { cacheItem.Item = Serialize(entry); cacheItem.Expiration = utcExpiry; _cacheItems.Save(cacheItem); } else { _cacheItems.Insert(new CacheItem { Id = key, Item = Serialize(entry), Expiration = utcExpiry }); } } public override void Remove(string key) { Debug.WriteLine("Cache.Remove({0})", key); var query = MongoDB.Driver.Builders.Query.EQ("_id", key); _cacheItems.Remove(query); } private static string Md5(string value) { var cryptoServiceProvider = new MD5CryptoServiceProvider(); var bytes = Encoding.UTF8.GetBytes(value); var builder = new StringBuilder(); bytes = cryptoServiceProvider.ComputeHash(bytes); foreach (var b in bytes) builder.Append(b.ToString("x2").ToLower()); return builder.ToString(); } private static byte[] Serialize(object entry) { var formatter = new BinaryFormatter(); var stream = new MemoryStream(); formatter.Serialize(stream, entry); return stream.ToArray(); } private static object Deserialize(byte[] serializedEntry) { var formatter = new BinaryFormatter(); var stream = new MemoryStream(serializedEntry); return formatter.Deserialize(stream); } } }