From 4223bdfbe4be759cc170faecf1e407046180e02a Mon Sep 17 00:00:00 2001 From: James South Date: Sat, 21 Feb 2015 16:51:47 +0000 Subject: [PATCH] Pre release polish Former-commit-id: f18d297cafde4ca9a7d6e9aeb40fa6e038044295 Former-commit-id: bbe58c41a02747a536016c8872319e4499623479 --- .../imageprocessor/cache.config.transform | 7 ++- src/ImageProcessor.Playground/Program.cs | 4 -- .../AzureBlobCache.cs | 48 ++++++++++--------- .../Caching/CacheIndexer.cs | 4 +- src/ImageProcessor.Web/Caching/DiskCache.cs | 22 +-------- src/ImageProcessor.Web/Caching/IImageCache.cs | 8 ++-- .../Caching/ImageCacheBase.cs | 9 ++-- src/ImageProcessor.Web/Caching/MemCache.cs | 13 ++--- .../Configuration/ImageCacheSection.cs | 20 ++++++++ .../Configuration/ImageProcessingSection.cs | 6 --- .../ImageProcessorConfiguration.cs | 7 ++- .../Resources/cache.config.transform | 3 +- src/ImageProcessor.Web/Helpers/RemoteFile.cs | 2 - .../HttpModules/ImageProcessingModule.cs | 16 ++++--- .../MVC/Views/Home/External.cshtml | 6 +-- .../MVC/config/imageprocessor/cache.config | 4 +- 16 files changed, 85 insertions(+), 94 deletions(-) diff --git a/build/content/ImageProcessor.Web.AzureBlobCache/config/imageprocessor/cache.config.transform b/build/content/ImageProcessor.Web.AzureBlobCache/config/imageprocessor/cache.config.transform index 16974d815..6376f2801 100644 --- a/build/content/ImageProcessor.Web.AzureBlobCache/config/imageprocessor/cache.config.transform +++ b/build/content/ImageProcessor.Web.AzureBlobCache/config/imageprocessor/cache.config.transform @@ -1,13 +1,12 @@ - + - - - + + diff --git a/src/ImageProcessor.Playground/Program.cs b/src/ImageProcessor.Playground/Program.cs index 31a4eb320..3c90df9bb 100644 --- a/src/ImageProcessor.Playground/Program.cs +++ b/src/ImageProcessor.Playground/Program.cs @@ -39,10 +39,6 @@ namespace ImageProcessor.PlayGround /// public static void Main(string[] args) { - var x = typeof(AzureBlobCache); - Console.WriteLine(x.AssemblyQualifiedName); - Console.ReadLine(); - string path = new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath; // ReSharper disable once AssignNullToNotNullAttribute diff --git a/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs b/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs index a206938f8..fca2bcbf1 100644 --- a/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs +++ b/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs @@ -23,6 +23,7 @@ namespace ImageProcessor.Web.Caching using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; + using ImageProcessor.Web.HttpModules; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; @@ -34,9 +35,14 @@ namespace ImageProcessor.Web.Caching public class AzureBlobCache : ImageCacheBase { /// - /// The maximum number of days to store the image. + /// The regular expression for parsing a remote uri. /// - private readonly int maxDays; + private static readonly Regex RemoteRegex = new Regex("^http(s)?://", RegexOptions.Compiled); + + /// + /// The assembly version. + /// + private static readonly string AssemblyVersion = typeof(ImageProcessingModule).Assembly.GetName().Version.ToString(); /// /// The cloud cached blob container. @@ -73,32 +79,26 @@ namespace ImageProcessor.Web.Caching public AzureBlobCache(string requestPath, string fullPath, string querystring) : base(requestPath, fullPath, querystring) { - this.maxDays = Convert.ToInt32(this.Settings["MaxDays"]); - // Retrieve storage accounts from connection string. CloudStorageAccount cloudCachedStorageAccount = CloudStorageAccount.Parse(this.Settings["CachedStorageAccount"]); - CloudStorageAccount cloudSourceStorageAccount = CloudStorageAccount.Parse(this.Settings["SourceStorageAccount"]); // Create the blob clients. CloudBlobClient cloudCachedBlobClient = cloudCachedStorageAccount.CreateCloudBlobClient(); - CloudBlobClient cloudSourceBlobClient = cloudSourceStorageAccount.CreateCloudBlobClient(); // Retrieve references to a previously created containers. this.cloudCachedBlobContainer = cloudCachedBlobClient.GetContainerReference(this.Settings["CachedBlobContainer"]); - this.cloudSourceBlobContainer = cloudSourceBlobClient.GetContainerReference(this.Settings["SourceBlobContainer"]); - this.cachedCdnRoot = this.Settings["CachedCDNRoot"]; - } + string sourceAccount = this.Settings.ContainsKey("SourceStorageAccount") ? this.Settings["SourceStorageAccount"] : string.Empty; - /// - /// Gets the maximum number of days to store the image. - /// - public override int MaxDays - { - get + // Repeat for source if it exists + if (!string.IsNullOrWhiteSpace(sourceAccount)) { - return this.maxDays; + CloudStorageAccount cloudSourceStorageAccount = CloudStorageAccount.Parse(this.Settings["SourceStorageAccount"]); + CloudBlobClient cloudSourceBlobClient = cloudSourceStorageAccount.CreateCloudBlobClient(); + this.cloudSourceBlobContainer = cloudSourceBlobClient.GetContainerReference(this.Settings["SourceBlobContainer"]); } + + this.cachedCdnRoot = this.Settings.ContainsKey("CachedCDNRoot") ? this.Settings["CachedCDNRoot"] : string.Empty; } /// @@ -109,7 +109,7 @@ namespace ImageProcessor.Web.Caching /// public override async Task IsNewOrUpdatedAsync() { - string cachedFileName = await this.CreateCachedFileName(); + string cachedFileName = await this.CreateCachedFileNameAsync(); // Collision rate of about 1 in 10000 for the folder structure. // That gives us massive scope to store millions of files. @@ -118,7 +118,7 @@ namespace ImageProcessor.Web.Caching this.cachedRewritePath = Path.Combine(this.cachedCdnRoot, this.cloudCachedBlobContainer.Name, pathFromKey, cachedFileName).Replace(@"\", "/"); bool isUpdated = false; - CachedImage cachedImage = CacheIndexer.GetValue(this.CachedPath); + CachedImage cachedImage = CacheIndexer.Get(this.CachedPath); if (new Uri(this.CachedPath).IsFile) { @@ -205,6 +205,9 @@ namespace ImageProcessor.Web.Caching blockBlob.Properties.ContentType = contentType; blockBlob.Properties.CacheControl = string.Format("public, max-age={0}", this.MaxDays * 86400); await blockBlob.SetPropertiesAsync(); + + blockBlob.Metadata.Add("ImageProcessedBy", "ImageProcessor.Web/" + AssemblyVersion); + await blockBlob.SetMetadataAsync(); } /// @@ -257,7 +260,7 @@ namespace ImageProcessor.Web.Caching /// /// The asynchronous returning the value. /// - public override async Task CreateCachedFileName() + public override async Task CreateCachedFileNameAsync() { string streamHash = string.Empty; @@ -279,11 +282,10 @@ namespace ImageProcessor.Web.Caching streamHash = string.Format("{0}{1}", creation, length); } } - else + else if (this.cloudSourceBlobContainer != null) { - Regex regex = new Regex("^http(s)?://"); - string container = regex.Replace(this.cloudSourceBlobContainer.Uri.ToString(), string.Empty); - string blobPath = regex.Replace(this.RequestPath, string.Empty); + string container = RemoteRegex.Replace(this.cloudSourceBlobContainer.Uri.ToString(), string.Empty); + string blobPath = RemoteRegex.Replace(this.RequestPath, string.Empty); blobPath = blobPath.Replace(container, string.Empty).TrimStart('/'); CloudBlockBlob blockBlob = this.cloudSourceBlobContainer.GetBlockBlobReference(blobPath); diff --git a/src/ImageProcessor.Web/Caching/CacheIndexer.cs b/src/ImageProcessor.Web/Caching/CacheIndexer.cs index 39654e83a..1b4b581cd 100644 --- a/src/ImageProcessor.Web/Caching/CacheIndexer.cs +++ b/src/ImageProcessor.Web/Caching/CacheIndexer.cs @@ -20,7 +20,6 @@ namespace ImageProcessor.Web.Caching /// public static class CacheIndexer { - #region Public /// /// Gets the associated with the specified key. /// @@ -31,7 +30,7 @@ namespace ImageProcessor.Web.Caching /// The matching the given key if the contains an element with /// the specified key; otherwise, null. /// - public static CachedImage GetValue(string cachedPath) + public static CachedImage Get(string cachedPath) { string key = Path.GetFileNameWithoutExtension(cachedPath); CachedImage cachedImage = (CachedImage)MemCache.GetItem(key); @@ -80,6 +79,5 @@ namespace ImageProcessor.Web.Caching return cachedImage; } - #endregion } } \ No newline at end of file diff --git a/src/ImageProcessor.Web/Caching/DiskCache.cs b/src/ImageProcessor.Web/Caching/DiskCache.cs index e02cd4e24..1c9040e40 100644 --- a/src/ImageProcessor.Web/Caching/DiskCache.cs +++ b/src/ImageProcessor.Web/Caching/DiskCache.cs @@ -11,7 +11,6 @@ namespace ImageProcessor.Web.Caching { - using System; using System.Collections.Generic; using System.Configuration; using System.IO; @@ -40,11 +39,6 @@ namespace ImageProcessor.Web.Caching /// private const int MaxFilesCount = 100; - /// - /// The maximum number of days to store the image. - /// - private readonly int maxDays; - /// /// The virtual cache path. /// @@ -75,7 +69,6 @@ namespace ImageProcessor.Web.Caching public DiskCache(string requestPath, string fullPath, string querystring) : base(requestPath, fullPath, querystring) { - this.maxDays = Convert.ToInt32(this.Settings["MaxDays"]); string virtualPath = this.Settings["VirtualCachePath"]; if (!virtualPath.IsValidVirtualPathName()) @@ -88,17 +81,6 @@ namespace ImageProcessor.Web.Caching this.absoluteCachePath = HostingEnvironment.MapPath(this.virtualCachePath); } - /// - /// Gets the maximum number of days to store the image. - /// - public override int MaxDays - { - get - { - return this.maxDays; - } - } - /// /// Gets a value indicating whether the image is new or updated in an asynchronous manner. /// @@ -107,7 +89,7 @@ namespace ImageProcessor.Web.Caching /// public override async Task IsNewOrUpdatedAsync() { - string cachedFileName = await this.CreateCachedFileName(); + string cachedFileName = await this.CreateCachedFileNameAsync(); // Collision rate of about 1 in 10000 for the folder structure. // That gives us massive scope to store millions of files. @@ -117,7 +99,7 @@ namespace ImageProcessor.Web.Caching this.virtualCachedFilePath = Path.Combine(this.virtualCachePath, virtualPathFromKey, cachedFileName).Replace(@"\", "/"); bool isUpdated = false; - CachedImage cachedImage = CacheIndexer.GetValue(this.CachedPath); + CachedImage cachedImage = CacheIndexer.Get(this.CachedPath); if (cachedImage == null) { diff --git a/src/ImageProcessor.Web/Caching/IImageCache.cs b/src/ImageProcessor.Web/Caching/IImageCache.cs index 9c9214824..cff12b47b 100644 --- a/src/ImageProcessor.Web/Caching/IImageCache.cs +++ b/src/ImageProcessor.Web/Caching/IImageCache.cs @@ -31,9 +31,9 @@ namespace ImageProcessor.Web.Caching string CachedPath { get; } /// - /// Gets the maximum number of days to store the image. + /// Gets or sets the maximum number of days to store the image. /// - int MaxDays { get; } + int MaxDays { get; set; } /// /// Gets a value indicating whether the image is new or updated in an asynchronous manner. @@ -66,12 +66,12 @@ namespace ImageProcessor.Web.Caching Task TrimCacheAsync(); /// - /// Gets a string identifying the cached file name. + /// Gets a string identifying the cached file name in an asynchronous manner. /// /// /// The asynchronous returning the value. /// - Task CreateCachedFileName(); + Task CreateCachedFileNameAsync(); /// /// Rewrites the path to point to the cached image. diff --git a/src/ImageProcessor.Web/Caching/ImageCacheBase.cs b/src/ImageProcessor.Web/Caching/ImageCacheBase.cs index 4a036a2f6..cec6886ab 100644 --- a/src/ImageProcessor.Web/Caching/ImageCacheBase.cs +++ b/src/ImageProcessor.Web/Caching/ImageCacheBase.cs @@ -61,6 +61,7 @@ namespace ImageProcessor.Web.Caching this.FullPath = fullPath; this.Querystring = querystring; this.Settings = ImageProcessorConfiguration.Instance.ImageCacheSettings; + this.MaxDays = ImageProcessorConfiguration.Instance.ImageCacheMaxDays; } /// @@ -74,9 +75,9 @@ namespace ImageProcessor.Web.Caching public string CachedPath { get; set; } /// - /// Gets the maximum number of days to store the image. + /// Gets or sets the maximum number of days to store the image. /// - public abstract int MaxDays { get; } + public int MaxDays { get; set; } /// /// Gets a value indicating whether the image is new or updated in an asynchronous manner. @@ -114,7 +115,7 @@ namespace ImageProcessor.Web.Caching /// /// The asynchronous returning the value. /// - public virtual Task CreateCachedFileName() + public virtual async Task CreateCachedFileNameAsync() { string streamHash = string.Empty; @@ -153,7 +154,7 @@ namespace ImageProcessor.Web.Caching encryptedName, !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : "jpg"); - return Task.FromResult(cachedFileName); + return await Task.FromResult(cachedFileName); } /// diff --git a/src/ImageProcessor.Web/Caching/MemCache.cs b/src/ImageProcessor.Web/Caching/MemCache.cs index a20971b98..192a7b7b7 100644 --- a/src/ImageProcessor.Web/Caching/MemCache.cs +++ b/src/ImageProcessor.Web/Caching/MemCache.cs @@ -10,19 +10,16 @@ namespace ImageProcessor.Web.Caching { - #region Using using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Runtime.Caching; - #endregion /// /// Encapsulates methods that allow the caching and retrieval of objects from the in memory cache. /// internal static class MemCache { - #region Fields /// /// The cache /// @@ -32,9 +29,7 @@ namespace ImageProcessor.Web.Caching /// An internal list of cache keys to allow bulk removal. /// private static readonly ConcurrentDictionary CacheItems = new ConcurrentDictionary(); - #endregion - #region Methods /// /// Adds an item to the cache. /// @@ -105,7 +100,10 @@ namespace ImageProcessor.Web.Caching /// public static object GetItem(string key, string regionName = null) { - return Cache.Get(key, regionName); + lock (Cache) + { + return Cache.Get(key, regionName); + } } /// @@ -131,7 +129,7 @@ namespace ImageProcessor.Web.Caching /// True if the update try succeeds, or false if there is an already an entry /// in the cache with the same key as key. /// - public static bool UpdateItem(string key, object value, CacheItemPolicy policy = null, string regionName = null) + public static bool UpdateItem(string key, object value, CacheItemPolicy policy = null, string regionName = null) { bool isUpDated = true; @@ -237,6 +235,5 @@ namespace ImageProcessor.Web.Caching return isCleared; } - #endregion } } diff --git a/src/ImageProcessor.Web/Configuration/ImageCacheSection.cs b/src/ImageProcessor.Web/Configuration/ImageCacheSection.cs index 71c25e3e3..e365b0fba 100644 --- a/src/ImageProcessor.Web/Configuration/ImageCacheSection.cs +++ b/src/ImageProcessor.Web/Configuration/ImageCacheSection.cs @@ -103,6 +103,26 @@ namespace ImageProcessor.Web.Configuration set { this["type"] = value; } } + /// + /// Gets or sets the maximum number of days to store an image in the cache. + /// + /// The maximum number of days to store an image in the cache. + /// Defaults to 365 if not set. + [ConfigurationProperty("maxDays", DefaultValue = "365", IsRequired = true)] + [IntegerValidator(ExcludeRange = false, MinValue = 0)] + public int MaxDays + { + get + { + return (int)this["maxDays"]; + } + + set + { + this["maxDays"] = value; + } + } + /// /// Gets the . /// diff --git a/src/ImageProcessor.Web/Configuration/ImageProcessingSection.cs b/src/ImageProcessor.Web/Configuration/ImageProcessingSection.cs index 52b0bc932..94598dd20 100644 --- a/src/ImageProcessor.Web/Configuration/ImageProcessingSection.cs +++ b/src/ImageProcessor.Web/Configuration/ImageProcessingSection.cs @@ -23,8 +23,6 @@ namespace ImageProcessor.Web.Configuration /// public sealed class ImageProcessingSection : ConfigurationSection { - #region Properties - /// /// Gets or sets a value indicating whether to preserve exif meta data. /// @@ -69,9 +67,7 @@ namespace ImageProcessor.Web.Configuration /// Gets or sets a value indicating whether to auto load plugins. /// public bool AutoLoadPlugins { get; set; } - #endregion - #region Methods /// /// Retrieves the processing configuration section from the current application configuration. /// @@ -95,8 +91,6 @@ namespace ImageProcessor.Web.Configuration return imageProcessingSection; } - #endregion - /// /// Represents a PresetElement configuration element within the configuration. /// diff --git a/src/ImageProcessor.Web/Configuration/ImageProcessorConfiguration.cs b/src/ImageProcessor.Web/Configuration/ImageProcessorConfiguration.cs index aaa3a3c4f..823c6447a 100644 --- a/src/ImageProcessor.Web/Configuration/ImageProcessorConfiguration.cs +++ b/src/ImageProcessor.Web/Configuration/ImageProcessorConfiguration.cs @@ -60,7 +60,6 @@ namespace ImageProcessor.Web.Configuration #endregion #region Constructors - /// /// Prevents a default instance of the class from being created. /// @@ -99,6 +98,11 @@ namespace ImageProcessor.Web.Configuration /// public Type ImageCache { get; private set; } + /// + /// Gets the image cache max days. + /// + public int ImageCacheMaxDays { get; private set; } + /// /// Gets the image cache settings. /// @@ -435,6 +439,7 @@ namespace ImageProcessor.Web.Configuration } this.ImageCache = type; + this.ImageCacheMaxDays = cache.MaxDays; this.ImageCacheSettings = cache.Settings .Cast() .ToDictionary(setting => setting.Key, setting => setting.Value); diff --git a/src/ImageProcessor.Web/Configuration/Resources/cache.config.transform b/src/ImageProcessor.Web/Configuration/Resources/cache.config.transform index 301a44e2b..8cad5133d 100644 --- a/src/ImageProcessor.Web/Configuration/Resources/cache.config.transform +++ b/src/ImageProcessor.Web/Configuration/Resources/cache.config.transform @@ -1,8 +1,7 @@ - + - diff --git a/src/ImageProcessor.Web/Helpers/RemoteFile.cs b/src/ImageProcessor.Web/Helpers/RemoteFile.cs index cf2950c1d..0d866132a 100644 --- a/src/ImageProcessor.Web/Helpers/RemoteFile.cs +++ b/src/ImageProcessor.Web/Helpers/RemoteFile.cs @@ -10,7 +10,6 @@ namespace ImageProcessor.Web.Helpers { - #region Using using System; using System.Collections.Generic; using System.Globalization; @@ -18,7 +17,6 @@ namespace ImageProcessor.Web.Helpers using System.Security; using System.Threading.Tasks; using System.Web; - #endregion /// /// Encapsulates methods used to download files from a website address. diff --git a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs index ae07b8e63..73e44778f 100644 --- a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs @@ -470,15 +470,15 @@ namespace ImageProcessor.Web.HttpModules /// private void SetHeaders(HttpContext context, string responseType, IEnumerable dependencyPaths) { - HttpResponse response = context.Response; - - if (response.Headers["Image-Served-By"] == null) - { - response.AddHeader("Image-Served-By", "ImageProcessor.Web/" + AssemblyVersion); - } - if (this.imageCache != null) { + HttpResponse response = context.Response; + + if (response.Headers["ImageProcessedBy"] == null) + { + response.AddHeader("ImageProcessedBy", "ImageProcessor.Web/" + AssemblyVersion); + } + HttpCachePolicy cache = response.Cache; cache.SetCacheability(HttpCacheability.Public); cache.VaryByHeaders["Accept-Encoding"] = true; @@ -499,6 +499,8 @@ namespace ImageProcessor.Web.HttpModules cache.SetExpires(DateTime.Now.ToUniversalTime().AddDays(maxDays)); cache.SetMaxAge(new TimeSpan(maxDays, 0, 0, 0)); cache.SetRevalidation(HttpCacheRevalidation.AllCaches); + + this.imageCache = null; } } diff --git a/src/TestWebsites/MVC/Views/Home/External.cshtml b/src/TestWebsites/MVC/Views/Home/External.cshtml index 668f48863..93704628b 100644 --- a/src/TestWebsites/MVC/Views/Home/External.cshtml +++ b/src/TestWebsites/MVC/Views/Home/External.cshtml @@ -5,15 +5,15 @@
- +
- +
- +
diff --git a/src/TestWebsites/MVC/config/imageprocessor/cache.config b/src/TestWebsites/MVC/config/imageprocessor/cache.config index 5dee07828..0ddede8b8 100644 --- a/src/TestWebsites/MVC/config/imageprocessor/cache.config +++ b/src/TestWebsites/MVC/config/imageprocessor/cache.config @@ -1,11 +1,9 @@  - + - -