namespace ImageProcessor.Web.Caching { using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Reflection; using System.Threading.Tasks; using System.Web; using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; public abstract class ImageCacheBase : IImageCache { /// /// The request path for the image. /// protected readonly string RequestPath; /// /// The full path for the image. /// protected readonly string FullPath; /// /// The querystring containing processing instructions. /// protected readonly string Querystring; /// /// The assembly version. /// private static readonly string AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); /// /// Initializes a new instance of the class. /// /// /// The request path for the image. /// /// /// The full path for the image. /// /// /// The querystring containing instructions. /// protected ImageCacheBase(string requestPath, string fullPath, string querystring) { this.RequestPath = requestPath; this.FullPath = fullPath; this.Querystring = querystring; } /// /// Gets any additional settings required by the cache. /// public Dictionary Settings { get; set; } public string CachedPath { get; protected set; } public abstract int MaxAge { get; } public abstract Task IsNewOrUpdatedAsync(); public abstract Task AddImageToCacheAsync(Stream stream); public abstract Task TrimCacheAsync(); public virtual Task CreateCachedFileName() { string streamHash = string.Empty; try { if (new Uri(this.RequestPath).IsFile) { // Get the hash for the filestream. That way we can ensure that if the image is // updated but has the same name we will know. FileInfo imageFileInfo = new FileInfo(this.RequestPath); if (imageFileInfo.Exists) { // Pull the latest info. imageFileInfo.Refresh(); // Checking the stream itself is far too processor intensive so we make a best guess. string creation = imageFileInfo.CreationTimeUtc.ToString(CultureInfo.InvariantCulture); string length = imageFileInfo.Length.ToString(CultureInfo.InvariantCulture); streamHash = string.Format("{0}{1}", creation, length); } } } catch { streamHash = string.Empty; } // Use an sha1 hash of the full path including the querystring to create the image name. // That name can also be used as a key for the cached image and we should be able to use // The characters of that hash as sub-folders. string parsedExtension = ImageHelpers.GetExtension(this.FullPath, this.Querystring); string encryptedName = (streamHash + this.FullPath).ToSHA1Fingerprint(); string cachedFileName = string.Format( "{0}.{1}", encryptedName, !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : "jpg"); return Task.FromResult(cachedFileName); } public abstract void RewritePath(HttpContext context); /// /// Gets a value indicating whether the given images creation date is out with /// the prescribed limit. /// /// /// The creation date. /// /// /// The true if the date is out with the limit, otherwise; false. /// protected virtual bool IsExpired(DateTime creationDate) { return creationDate.AddDays(this.MaxAge) < DateTime.UtcNow.AddDays(-this.MaxAge); } } }