diff --git a/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs b/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs index dc6e1a74c..6bda004f3 100644 --- a/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs +++ b/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs @@ -1,4 +1,15 @@ -namespace ImageProcessor.Web.Caching +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides an implementation that uses Azure blob storage. +// The cache is self healing and cleaning. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Caching { using System; using System.Collections.Generic; @@ -15,54 +26,72 @@ using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; + /// + /// Provides an implementation that uses Azure blob storage. + /// The cache is self healing and cleaning. + /// public class AzureBlobCache : ImageCacheBase { /// - /// The max age. + /// The maximum number of days to store the image. /// private readonly int maxDays; - private CloudStorageAccount cloudCachedStorageAccount; - - private CloudStorageAccount cloudSourceStorageAccount; - - private CloudBlobClient cloudCachedBlobClient; - - private CloudBlobClient cloudSourceBlobClient; - - private CloudBlobContainer cloudCachedBlobContainer; + /// + /// The cloud cached blob container. + /// + private readonly CloudBlobContainer cloudCachedBlobContainer; - private CloudBlobContainer cloudSourceBlobContainer; + /// + /// The cloud source blob container. + /// + private readonly CloudBlobContainer cloudSourceBlobContainer; - private string cachedCDNRoot; + /// + /// The cached root url for a content delivery network. + /// + private readonly string cachedCdnRoot; + /// + /// The cached rewrite path. + /// private string cachedRewritePath; /// - /// The physical cached path. + /// Initializes a new instance of the class. /// - private string physicalCachedPath; - + /// + /// The request path for the image. + /// + /// + /// The full path for the image. + /// + /// + /// The querystring containing instructions. + /// 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. - this.cloudCachedStorageAccount = CloudStorageAccount.Parse(this.Settings["CachedStorageAccount"]); - this.cloudSourceStorageAccount = CloudStorageAccount.Parse(this.Settings["SourceStorageAccount"]); + CloudStorageAccount cloudCachedStorageAccount = CloudStorageAccount.Parse(this.Settings["CachedStorageAccount"]); + CloudStorageAccount cloudSourceStorageAccount = CloudStorageAccount.Parse(this.Settings["SourceStorageAccount"]); // Create the blob clients. - this.cloudCachedBlobClient = this.cloudCachedStorageAccount.CreateCloudBlobClient(); - this.cloudSourceBlobClient = this.cloudSourceStorageAccount.CreateCloudBlobClient(); + CloudBlobClient cloudCachedBlobClient = cloudCachedStorageAccount.CreateCloudBlobClient(); + CloudBlobClient cloudSourceBlobClient = cloudSourceStorageAccount.CreateCloudBlobClient(); // Retrieve references to a previously created containers. - this.cloudCachedBlobContainer = this.cloudCachedBlobClient.GetContainerReference(this.Settings["CachedBlobContainer"]); - this.cloudSourceBlobContainer = this.cloudSourceBlobClient.GetContainerReference(this.Settings["SourceBlobContainer"]); + this.cloudCachedBlobContainer = cloudCachedBlobClient.GetContainerReference(this.Settings["CachedBlobContainer"]); + this.cloudSourceBlobContainer = cloudSourceBlobClient.GetContainerReference(this.Settings["SourceBlobContainer"]); - this.cachedCDNRoot = this.Settings["CachedCDNRoot"]; + this.cachedCdnRoot = this.Settings["CachedCDNRoot"]; } + /// + /// Gets the maximum number of days to store the image. + /// public override int MaxDays { get @@ -71,6 +100,12 @@ } } + /// + /// Gets a value indicating whether the image is new or updated in an asynchronous manner. + /// + /// + /// The asynchronous returning the value. + /// public override async Task IsNewOrUpdatedAsync() { string cachedFileName = await this.CreateCachedFileName(); @@ -79,7 +114,7 @@ // That gives us massive scope to store millions of files. string pathFromKey = string.Join("\\", cachedFileName.ToCharArray().Take(6)); this.CachedPath = Path.Combine(this.cloudCachedBlobContainer.Uri.ToString(), pathFromKey, cachedFileName).Replace(@"\", "/"); - this.cachedRewritePath = Path.Combine(this.cachedCDNRoot, this.cloudCachedBlobContainer.Name, pathFromKey, cachedFileName).Replace(@"\", "/"); + this.cachedRewritePath = Path.Combine(this.cachedCdnRoot, this.cloudCachedBlobContainer.Name, pathFromKey, cachedFileName).Replace(@"\", "/"); bool isUpdated = false; CachedImage cachedImage = CacheIndexer.GetValue(this.CachedPath); @@ -147,18 +182,36 @@ return isUpdated; } + /// + /// Adds the image to the cache in an asynchronous manner. + /// + /// + /// The stream containing the image data. + /// + /// + /// The content type of the image. + /// + /// + /// The representing an asynchronous operation. + /// public override async Task AddImageToCacheAsync(Stream stream, string contentType) { string blobPath = this.CachedPath.Substring(this.cloudCachedBlobContainer.Uri.ToString().Length + 1); CloudBlockBlob blockBlob = this.cloudCachedBlobContainer.GetBlockBlobReference(blobPath); await blockBlob.UploadFromStreamAsync(stream); - + blockBlob.Properties.ContentType = contentType; blockBlob.Properties.CacheControl = string.Format("public, max-age={0}", this.MaxDays * 86400); await blockBlob.SetPropertiesAsync(); } + /// + /// Trims the cache of any expired items in an asynchronous manner. + /// + /// + /// The asynchronous representing an asynchronous operation. + /// public override async Task TrimCacheAsync() { Uri uri = new Uri(this.CachedPath); @@ -197,6 +250,12 @@ } } + /// + /// Gets a string identifying the cached file name. + /// + /// + /// The asynchronous returning the value. + /// public override async Task CreateCachedFileName() { string streamHash = string.Empty; @@ -260,6 +319,12 @@ return cachedFileName; } + /// + /// Rewrites the path to point to the cached image. + /// + /// + /// The encapsulating all information about the request. + /// public override void RewritePath(HttpContext context) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.cachedRewritePath); diff --git a/src/ImageProcessor.Web/Caching/DiskCache.cs b/src/ImageProcessor.Web/Caching/DiskCache.cs index 451183526..e02cd4e24 100644 --- a/src/ImageProcessor.Web/Caching/DiskCache.cs +++ b/src/ImageProcessor.Web/Caching/DiskCache.cs @@ -1,4 +1,15 @@ -namespace ImageProcessor.Web.Caching +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides an implementation that is file system based. +// The cache is self healing and cleaning. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Caching { using System; using System.Collections.Generic; @@ -9,9 +20,12 @@ using System.Web; using System.Web.Hosting; - using ImageProcessor.Web.Configuration; using ImageProcessor.Web.Extensions; + /// + /// Provides an implementation that is file system based. + /// The cache is self healing and cleaning. + /// public class DiskCache : ImageCacheBase { /// @@ -27,7 +41,7 @@ private const int MaxFilesCount = 100; /// - /// The max age. + /// The maximum number of days to store the image. /// private readonly int maxDays; @@ -42,7 +56,7 @@ private readonly string absoluteCachePath; /// - /// The virtual cached path to the cached file. + /// The virtual path to the cached file. /// private string virtualCachedFilePath; @@ -75,8 +89,7 @@ } /// - /// The maximum number of days to cache files on the system for. - /// TODO: Shift the getter source to proper config. + /// Gets the maximum number of days to store the image. /// public override int MaxDays { @@ -86,6 +99,12 @@ } } + /// + /// Gets a value indicating whether the image is new or updated in an asynchronous manner. + /// + /// + /// The . + /// public override async Task IsNewOrUpdatedAsync() { string cachedFileName = await this.CreateCachedFileName(); @@ -138,6 +157,18 @@ return isUpdated; } + /// + /// Adds the image to the cache in an asynchronous manner. + /// + /// + /// The stream containing the image data. + /// + /// + /// The content type of the image. + /// + /// + /// The representing an asynchronous operation. + /// public override async Task AddImageToCacheAsync(Stream stream, string contentType) { // ReSharper disable once AssignNullToNotNullAttribute @@ -153,6 +184,12 @@ } } + /// + /// Trims the cache of any expired items in an asynchronous manner. + /// + /// + /// The asynchronous representing an asynchronous operation. + /// public override async Task TrimCacheAsync() { string directory = Path.GetDirectoryName(this.CachedPath); @@ -198,6 +235,12 @@ } } + /// + /// Rewrites the path to point to the cached image. + /// + /// + /// The encapsulating all information about the request. + /// public override void RewritePath(HttpContext context) { // The cached file is valid so just rewrite the path. diff --git a/src/ImageProcessor.Web/Caching/IImageCache.cs b/src/ImageProcessor.Web/Caching/IImageCache.cs index 976d47012..9c9214824 100644 --- a/src/ImageProcessor.Web/Caching/IImageCache.cs +++ b/src/ImageProcessor.Web/Caching/IImageCache.cs @@ -1,4 +1,13 @@ - +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Defines properties and methods for allowing caching of images to different sources. +// +// -------------------------------------------------------------------------------------------------------------------- + namespace ImageProcessor.Web.Caching { using System.Collections.Generic; @@ -6,6 +15,9 @@ namespace ImageProcessor.Web.Caching using System.Threading.Tasks; using System.Web; + /// + /// Defines properties and methods for allowing caching of images to different sources. + /// public interface IImageCache { /// @@ -13,20 +25,60 @@ namespace ImageProcessor.Web.Caching /// Dictionary Settings { get; set; } + /// + /// Gets the path to the cached image. + /// string CachedPath { get; } + /// + /// Gets the maximum number of days to store the image. + /// int MaxDays { get; } + /// + /// Gets a value indicating whether the image is new or updated in an asynchronous manner. + /// + /// + /// The asynchronous returning the value. + /// Task IsNewOrUpdatedAsync(); + /// + /// Adds the image to the cache in an asynchronous manner. + /// + /// + /// The stream containing the image data. + /// + /// + /// The content type of the image. + /// + /// + /// The representing an asynchronous operation. + /// Task AddImageToCacheAsync(Stream stream, string contentType); + /// + /// Trims the cache of any expired items in an asynchronous manner. + /// + /// + /// The asynchronous representing an asynchronous operation. + /// Task TrimCacheAsync(); + /// + /// Gets a string identifying the cached file name. + /// + /// + /// The asynchronous returning the value. + /// Task CreateCachedFileName(); + /// + /// Rewrites the path to point to the cached image. + /// + /// + /// The encapsulating all information about the request. + /// void RewritePath(HttpContext context); - - //void SetHeaders(HttpContext context); } } diff --git a/src/ImageProcessor.Web/Caching/ImageCacheBase.cs b/src/ImageProcessor.Web/Caching/ImageCacheBase.cs index b49602501..4a036a2f6 100644 --- a/src/ImageProcessor.Web/Caching/ImageCacheBase.cs +++ b/src/ImageProcessor.Web/Caching/ImageCacheBase.cs @@ -1,10 +1,20 @@ -namespace ImageProcessor.Web.Caching +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// The image cache base provides methods for implementing the interface. +// It is recommended that any implementations inherit from this class. +// +// -------------------------------------------------------------------------------------------------------------------- + +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; @@ -12,6 +22,10 @@ using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; + /// + /// The image cache base provides methods for implementing the interface. + /// It is recommended that any implementations inherit from this class. + /// public abstract class ImageCacheBase : IImageCache { /// @@ -54,16 +68,52 @@ /// public Dictionary Settings { get; set; } - public string CachedPath { get; protected set; } + /// + /// Gets or sets the path to the cached image. + /// + public string CachedPath { get; set; } + /// + /// Gets the maximum number of days to store the image. + /// public abstract int MaxDays { get; } + /// + /// Gets a value indicating whether the image is new or updated in an asynchronous manner. + /// + /// + /// The . + /// public abstract Task IsNewOrUpdatedAsync(); + /// + /// Adds the image to the cache in an asynchronous manner. + /// + /// + /// The stream containing the image data. + /// + /// + /// The content type of the image. + /// + /// + /// The representing an asynchronous operation. + /// public abstract Task AddImageToCacheAsync(Stream stream, string contentType); + /// + /// Trims the cache of any expired items in an asynchronous manner. + /// + /// + /// The asynchronous representing an asynchronous operation. + /// public abstract Task TrimCacheAsync(); + /// + /// Gets a string identifying the cached file name. + /// + /// + /// The asynchronous returning the value. + /// public virtual Task CreateCachedFileName() { string streamHash = string.Empty; @@ -106,6 +156,12 @@ return Task.FromResult(cachedFileName); } + /// + /// Rewrites the path to point to the cached image. + /// + /// + /// The encapsulating all information about the request. + /// public abstract void RewritePath(HttpContext context); /// diff --git a/src/ImageProcessor.Web/Services/IImageService.cs b/src/ImageProcessor.Web/Services/IImageService.cs index dfdcf0cdc..c6c39f80f 100644 --- a/src/ImageProcessor.Web/Services/IImageService.cs +++ b/src/ImageProcessor.Web/Services/IImageService.cs @@ -4,7 +4,7 @@ // Licensed under the Apache License, Version 2.0. // // -// Defines properties and methods for allowing retrieval of image from different sources. +// Defines properties and methods for allowing retrieval of images from different sources. // // -------------------------------------------------------------------------------------------------------------------- @@ -15,7 +15,7 @@ namespace ImageProcessor.Web.Services using System.Threading.Tasks; /// - /// Defines properties and methods for allowing retrieval of image from different sources. + /// Defines properties and methods for allowing retrieval of images from different sources. /// public interface IImageService { diff --git a/src/ImageProcessor.Web/Settings.StyleCop b/src/ImageProcessor.Web/Settings.StyleCop index 09dd1de03..311872ed4 100644 --- a/src/ImageProcessor.Web/Settings.StyleCop +++ b/src/ImageProcessor.Web/Settings.StyleCop @@ -1,6 +1,7 @@ + cdn dllimport