using System; using System.Configuration; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Web; using System.Web.Caching; namespace FastReport.Web { /// /// /// public class WebReportCache { internal static string StoragePrefix = FastReport.Utils.Config.Version + "."; internal static string touchFilename = StoragePrefix + "touch"; internal static string maskStorage = StoragePrefix + "*"; private bool webFarmMode = false; private string fileStoragePath; private int fileStorageTimeout; private int storageCleanup; private int cacheDelay = 15; private CacheItemPriority priority = CacheItemPriority.Default; private readonly object locker = new object(); /// /// /// public bool WebFarmMode { get { return webFarmMode; } } /// /// /// public int Delay { get { return cacheDelay; } set { cacheDelay = value; } } /// /// /// public CacheItemPriority Priority { get { return priority; } set { priority = value; } } /// /// /// /// /// public void PutObject(string Name, Object Obj) { if (Obj != null) { lock (locker) { if (WebFarmMode) { if (Obj is WebReport) { WebReport webReport = Obj as WebReport; using(Stream propStream = webReport.GetPropData()) PutFileStorage(Name, propStream); using(Stream repStream = webReport.GetReportData()) PutFileStorage(Name + "report", repStream); using(Stream prepStream = webReport.GetPreparedData()) PutFileStorage(Name + "prepared", prepStream); } else PutFileStorage(Name, Obj); CleanFileStorage(); } else if (!String.IsNullOrEmpty(Name) && Obj != null) #if DOTNET_4 HttpRuntime.Cache.Insert( Name, Obj, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, cacheDelay, 0), UpdateCallback); #else HttpRuntime.Cache.Add( Name, Obj, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, cacheDelay, 0), priority, RemovedCallback); #endif } } } /// /// /// /// /// public object GetObject(string Name) { return GetObject(Name, null); } /// /// /// /// /// /// public object GetObject(string Name, Object obj) { lock (locker) { if (WebFarmMode) { if ((obj != null) && (obj is WebReport)) { WebReport webReport = obj as WebReport; using(Stream propStream = GetFileStorage(Name) as Stream) webReport.SetPropData(propStream); using (Stream reportStream = GetFileStorage(Name + "report") as Stream) webReport.SetReportData(reportStream); using (Stream preparedStream = GetFileStorage(Name + "prepared") as Stream) webReport.SetPreparedData(preparedStream); } else obj = GetFileStorage(Name); } else if (!String.IsNullOrEmpty(Name)) { Object cached_obj = HttpRuntime.Cache[Name]; if (cached_obj != null) obj = cached_obj; } } return obj; } /// /// /// /// public void Remove(string Name) { lock (locker) { if (!String.IsNullOrEmpty(Name)) { if (WebFarmMode) DeleteFileStorage(Name); else HttpRuntime.Cache.Remove(Name); } } } private void DeleteFileStorage(string Name) { string fileName = String.Concat(fileStoragePath, StoragePrefix, Name); if (File.Exists(fileName)) { try { File.Delete(fileName); } catch { // nothing } } } private string GetStoragePath(HttpContext context) { string path = ConfigurationManager.AppSettings["FastReportStoragePath"]; if (!String.IsNullOrEmpty(path)) { path += Path.DirectorySeparatorChar; if (!(path.StartsWith(@"\\") || path.StartsWith(@"//")) && (context != null)) path = context.Request.MapPath(path); } return path; } private int GetStorageTimeout() { string valueS = ConfigurationManager.AppSettings["FastReportStorageTimeout"]; int value = 15; if (!String.IsNullOrEmpty(valueS)) value = Convert.ToInt16(valueS); return value; } private int GetStorageCleanup() { string valueS = ConfigurationManager.AppSettings["FastReportStorageCleanup"]; int value = 1; if (!String.IsNullOrEmpty(valueS)) value = Convert.ToInt16(valueS); return value; } /// /// /// /// public int CleanFileStorage() { if (webFarmMode) { string touch = Path.Combine(fileStoragePath, touchFilename); if (!String.IsNullOrEmpty(fileStoragePath) && Directory.Exists(fileStoragePath)) { if (!File.Exists(touch)) { using (FileStream file = File.Create(touch)) { }; } else { DateTime created = File.GetLastWriteTime(touch); if (DateTime.Now > created.AddMinutes(storageCleanup)) { File.SetLastWriteTime(touch, DateTime.Now); string[] dir = Directory.GetFiles(fileStoragePath, maskStorage); foreach (string file in dir) { try { if (DateTime.Now > File.GetLastWriteTime(file).AddMinutes(fileStorageTimeout)) File.Delete(file); } catch { //nothing } } } } } return Directory.GetFiles(fileStoragePath, maskStorage).Length; } else return 0; } private object GetFileStorage(string name) { string fileName = String.Concat(fileStoragePath, StoragePrefix, name); object obj = null; if (File.Exists(fileName)) { try { File.SetLastWriteTime(fileName, DateTime.Now); } catch { }; using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { BinaryFormatter bf = new BinaryFormatter(); obj = bf.Deserialize(fs); } } return obj; } private void PutFileStorage(string name, object value) { string fileName = String.Concat(fileStoragePath, StoragePrefix, name); if (File.Exists(fileName)) { if (value is byte[]) { try { File.SetLastWriteTime(fileName, DateTime.Now); } catch { // nothing to do } } else try { File.Delete(fileName); } catch { // nothing to do } } if (!File.Exists(fileName)) { using (FileStream fs = new FileStream(fileName, FileMode.CreateNew)) { BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(fs, value); } } } #if DOTNET_4 private void UpdateCallback(string key, CacheItemUpdateReason reason, out Object expensiveObject, out CacheDependency dependency, out DateTime absoluteExpiration, out TimeSpan slidingExpiration) { Object v = HttpRuntime.Cache[key]; dependency = null; if (v!= null && v is WebReport) { WebReport webReport = v as WebReport; for (int i = 0; i < webReport.Tabs.Count; i++) { if (webReport.Tabs[i].Report.PreparedPages != null) webReport.Tabs[i].Report.PreparedPages.Clear(); webReport.Tabs[i].Properties.ReportDone = false; } expensiveObject = v; absoluteExpiration = Cache.NoAbsoluteExpiration; slidingExpiration = new TimeSpan(0, cacheDelay, 0); } else { expensiveObject = null; absoluteExpiration = DateTime.Now; slidingExpiration = new TimeSpan(0, 0, 0); } } #else private void RemovedCallback(String k, Object v, CacheItemRemovedReason r) { if (v is WebReport) { WebReport webReport = v as WebReport; try { if (webReport.Report.PreparedPages != null) webReport.Report.PreparedPages.Clear(); webReport.ReportDone = false; //PutObject(k, webReport); //webReport.Report.Dispose(); //webReport.Report = null; } catch { // nothing } } } #endif /// /// /// /// public WebReportCache(HttpContext context) { fileStoragePath = GetStoragePath(context); webFarmMode = !String.IsNullOrEmpty(fileStoragePath); fileStorageTimeout = GetStorageTimeout(); storageCleanup = GetStorageCleanup(); } } }