Browse Source

Pre release polish

Former-commit-id: f18d297cafde4ca9a7d6e9aeb40fa6e038044295
Former-commit-id: bbe58c41a02747a536016c8872319e4499623479
pull/17/head
James South 11 years ago
parent
commit
4223bdfbe4
  1. 7
      build/content/ImageProcessor.Web.AzureBlobCache/config/imageprocessor/cache.config.transform
  2. 4
      src/ImageProcessor.Playground/Program.cs
  3. 48
      src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs
  4. 4
      src/ImageProcessor.Web/Caching/CacheIndexer.cs
  5. 22
      src/ImageProcessor.Web/Caching/DiskCache.cs
  6. 8
      src/ImageProcessor.Web/Caching/IImageCache.cs
  7. 9
      src/ImageProcessor.Web/Caching/ImageCacheBase.cs
  8. 13
      src/ImageProcessor.Web/Caching/MemCache.cs
  9. 20
      src/ImageProcessor.Web/Configuration/ImageCacheSection.cs
  10. 6
      src/ImageProcessor.Web/Configuration/ImageProcessingSection.cs
  11. 7
      src/ImageProcessor.Web/Configuration/ImageProcessorConfiguration.cs
  12. 3
      src/ImageProcessor.Web/Configuration/Resources/cache.config.transform
  13. 2
      src/ImageProcessor.Web/Helpers/RemoteFile.cs
  14. 16
      src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs
  15. 6
      src/TestWebsites/MVC/Views/Home/External.cshtml
  16. 4
      src/TestWebsites/MVC/config/imageprocessor/cache.config

7
build/content/ImageProcessor.Web.AzureBlobCache/config/imageprocessor/cache.config.transform

@ -1,13 +1,12 @@
<caching currentCache="AzureBlobCache"> <caching currentCache="AzureBlobCache">
<caches> <caches>
<cache name="AzureBlobCache" type="ImageProcessor.Web.Caching.AzureBlobCache, ImageProcessor.Web.Caching.AzureBlobCache"> <cache name="AzureBlobCache" type="ImageProcessor.Web.Caching.AzureBlobCache, ImageProcessor.Web.Caching.AzureBlobCache" maxDays="365">
<settings> <settings>
<setting key="MaxDays" value="365"/>
<setting key="CachedStorageAccount" value="DefaultEndpointsProtocol=https;AccountName=[CacheAccountName];AccountKey=[CacheAccountKey]"/> <setting key="CachedStorageAccount" value="DefaultEndpointsProtocol=https;AccountName=[CacheAccountName];AccountKey=[CacheAccountKey]"/>
<setting key="SourceStorageAccount" value="DefaultEndpointsProtocol=https;AccountName=[SourceAccountName];AccountKey=[SourceAccountKey]"/>
<setting key="CachedBlobContainer" value="cache"/> <setting key="CachedBlobContainer" value="cache"/>
<setting key="SourceBlobContainer" value="source"/>
<setting key="CachedCDNRoot" value="[CdnRootUrl]"/> <setting key="CachedCDNRoot" value="[CdnRootUrl]"/>
<setting key="SourceStorageAccount" value=""/>
<setting key="SourceBlobContainer" value=""/>
</settings> </settings>
</cache> </cache>
</caches> </caches>

4
src/ImageProcessor.Playground/Program.cs

@ -39,10 +39,6 @@ namespace ImageProcessor.PlayGround
/// </param> /// </param>
public static void Main(string[] args) 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; string path = new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath;
// ReSharper disable once AssignNullToNotNullAttribute // ReSharper disable once AssignNullToNotNullAttribute

48
src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs

@ -23,6 +23,7 @@ namespace ImageProcessor.Web.Caching
using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Extensions;
using ImageProcessor.Web.Helpers; using ImageProcessor.Web.Helpers;
using ImageProcessor.Web.HttpModules;
using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob; using Microsoft.WindowsAzure.Storage.Blob;
@ -34,9 +35,14 @@ namespace ImageProcessor.Web.Caching
public class AzureBlobCache : ImageCacheBase public class AzureBlobCache : ImageCacheBase
{ {
/// <summary> /// <summary>
/// The maximum number of days to store the image. /// The regular expression for parsing a remote uri.
/// </summary> /// </summary>
private readonly int maxDays; private static readonly Regex RemoteRegex = new Regex("^http(s)?://", RegexOptions.Compiled);
/// <summary>
/// The assembly version.
/// </summary>
private static readonly string AssemblyVersion = typeof(ImageProcessingModule).Assembly.GetName().Version.ToString();
/// <summary> /// <summary>
/// The cloud cached blob container. /// The cloud cached blob container.
@ -73,32 +79,26 @@ namespace ImageProcessor.Web.Caching
public AzureBlobCache(string requestPath, string fullPath, string querystring) public AzureBlobCache(string requestPath, string fullPath, string querystring)
: base(requestPath, fullPath, querystring) : base(requestPath, fullPath, querystring)
{ {
this.maxDays = Convert.ToInt32(this.Settings["MaxDays"]);
// Retrieve storage accounts from connection string. // Retrieve storage accounts from connection string.
CloudStorageAccount cloudCachedStorageAccount = CloudStorageAccount.Parse(this.Settings["CachedStorageAccount"]); CloudStorageAccount cloudCachedStorageAccount = CloudStorageAccount.Parse(this.Settings["CachedStorageAccount"]);
CloudStorageAccount cloudSourceStorageAccount = CloudStorageAccount.Parse(this.Settings["SourceStorageAccount"]);
// Create the blob clients. // Create the blob clients.
CloudBlobClient cloudCachedBlobClient = cloudCachedStorageAccount.CreateCloudBlobClient(); CloudBlobClient cloudCachedBlobClient = cloudCachedStorageAccount.CreateCloudBlobClient();
CloudBlobClient cloudSourceBlobClient = cloudSourceStorageAccount.CreateCloudBlobClient();
// Retrieve references to a previously created containers. // Retrieve references to a previously created containers.
this.cloudCachedBlobContainer = cloudCachedBlobClient.GetContainerReference(this.Settings["CachedBlobContainer"]); 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;
}
/// <summary> // Repeat for source if it exists
/// Gets the maximum number of days to store the image. if (!string.IsNullOrWhiteSpace(sourceAccount))
/// </summary>
public override int MaxDays
{
get
{ {
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;
} }
/// <summary> /// <summary>
@ -109,7 +109,7 @@ namespace ImageProcessor.Web.Caching
/// </returns> /// </returns>
public override async Task<bool> IsNewOrUpdatedAsync() public override async Task<bool> IsNewOrUpdatedAsync()
{ {
string cachedFileName = await this.CreateCachedFileName(); string cachedFileName = await this.CreateCachedFileNameAsync();
// Collision rate of about 1 in 10000 for the folder structure. // Collision rate of about 1 in 10000 for the folder structure.
// That gives us massive scope to store millions of files. // 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(@"\", "/"); this.cachedRewritePath = Path.Combine(this.cachedCdnRoot, this.cloudCachedBlobContainer.Name, pathFromKey, cachedFileName).Replace(@"\", "/");
bool isUpdated = false; bool isUpdated = false;
CachedImage cachedImage = CacheIndexer.GetValue(this.CachedPath); CachedImage cachedImage = CacheIndexer.Get(this.CachedPath);
if (new Uri(this.CachedPath).IsFile) if (new Uri(this.CachedPath).IsFile)
{ {
@ -205,6 +205,9 @@ namespace ImageProcessor.Web.Caching
blockBlob.Properties.ContentType = contentType; blockBlob.Properties.ContentType = contentType;
blockBlob.Properties.CacheControl = string.Format("public, max-age={0}", this.MaxDays * 86400); blockBlob.Properties.CacheControl = string.Format("public, max-age={0}", this.MaxDays * 86400);
await blockBlob.SetPropertiesAsync(); await blockBlob.SetPropertiesAsync();
blockBlob.Metadata.Add("ImageProcessedBy", "ImageProcessor.Web/" + AssemblyVersion);
await blockBlob.SetMetadataAsync();
} }
/// <summary> /// <summary>
@ -257,7 +260,7 @@ namespace ImageProcessor.Web.Caching
/// <returns> /// <returns>
/// The asynchronous <see cref="Task"/> returning the value. /// The asynchronous <see cref="Task"/> returning the value.
/// </returns> /// </returns>
public override async Task<string> CreateCachedFileName() public override async Task<string> CreateCachedFileNameAsync()
{ {
string streamHash = string.Empty; string streamHash = string.Empty;
@ -279,11 +282,10 @@ namespace ImageProcessor.Web.Caching
streamHash = string.Format("{0}{1}", creation, length); streamHash = string.Format("{0}{1}", creation, length);
} }
} }
else else if (this.cloudSourceBlobContainer != null)
{ {
Regex regex = new Regex("^http(s)?://"); string container = RemoteRegex.Replace(this.cloudSourceBlobContainer.Uri.ToString(), string.Empty);
string container = regex.Replace(this.cloudSourceBlobContainer.Uri.ToString(), string.Empty); string blobPath = RemoteRegex.Replace(this.RequestPath, string.Empty);
string blobPath = regex.Replace(this.RequestPath, string.Empty);
blobPath = blobPath.Replace(container, string.Empty).TrimStart('/'); blobPath = blobPath.Replace(container, string.Empty).TrimStart('/');
CloudBlockBlob blockBlob = this.cloudSourceBlobContainer.GetBlockBlobReference(blobPath); CloudBlockBlob blockBlob = this.cloudSourceBlobContainer.GetBlockBlobReference(blobPath);

4
src/ImageProcessor.Web/Caching/CacheIndexer.cs

@ -20,7 +20,6 @@ namespace ImageProcessor.Web.Caching
/// </summary> /// </summary>
public static class CacheIndexer public static class CacheIndexer
{ {
#region Public
/// <summary> /// <summary>
/// Gets the <see cref="CachedImage"/> associated with the specified key. /// Gets the <see cref="CachedImage"/> associated with the specified key.
/// </summary> /// </summary>
@ -31,7 +30,7 @@ namespace ImageProcessor.Web.Caching
/// The <see cref="CachedImage"/> matching the given key if the <see cref="CacheIndexer"/> contains an element with /// The <see cref="CachedImage"/> matching the given key if the <see cref="CacheIndexer"/> contains an element with
/// the specified key; otherwise, null. /// the specified key; otherwise, null.
/// </returns> /// </returns>
public static CachedImage GetValue(string cachedPath) public static CachedImage Get(string cachedPath)
{ {
string key = Path.GetFileNameWithoutExtension(cachedPath); string key = Path.GetFileNameWithoutExtension(cachedPath);
CachedImage cachedImage = (CachedImage)MemCache.GetItem(key); CachedImage cachedImage = (CachedImage)MemCache.GetItem(key);
@ -80,6 +79,5 @@ namespace ImageProcessor.Web.Caching
return cachedImage; return cachedImage;
} }
#endregion
} }
} }

22
src/ImageProcessor.Web/Caching/DiskCache.cs

@ -11,7 +11,6 @@
namespace ImageProcessor.Web.Caching namespace ImageProcessor.Web.Caching
{ {
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Configuration; using System.Configuration;
using System.IO; using System.IO;
@ -40,11 +39,6 @@ namespace ImageProcessor.Web.Caching
/// </remarks> /// </remarks>
private const int MaxFilesCount = 100; private const int MaxFilesCount = 100;
/// <summary>
/// The maximum number of days to store the image.
/// </summary>
private readonly int maxDays;
/// <summary> /// <summary>
/// The virtual cache path. /// The virtual cache path.
/// </summary> /// </summary>
@ -75,7 +69,6 @@ namespace ImageProcessor.Web.Caching
public DiskCache(string requestPath, string fullPath, string querystring) public DiskCache(string requestPath, string fullPath, string querystring)
: base(requestPath, fullPath, querystring) : base(requestPath, fullPath, querystring)
{ {
this.maxDays = Convert.ToInt32(this.Settings["MaxDays"]);
string virtualPath = this.Settings["VirtualCachePath"]; string virtualPath = this.Settings["VirtualCachePath"];
if (!virtualPath.IsValidVirtualPathName()) if (!virtualPath.IsValidVirtualPathName())
@ -88,17 +81,6 @@ namespace ImageProcessor.Web.Caching
this.absoluteCachePath = HostingEnvironment.MapPath(this.virtualCachePath); this.absoluteCachePath = HostingEnvironment.MapPath(this.virtualCachePath);
} }
/// <summary>
/// Gets the maximum number of days to store the image.
/// </summary>
public override int MaxDays
{
get
{
return this.maxDays;
}
}
/// <summary> /// <summary>
/// Gets a value indicating whether the image is new or updated in an asynchronous manner. /// Gets a value indicating whether the image is new or updated in an asynchronous manner.
/// </summary> /// </summary>
@ -107,7 +89,7 @@ namespace ImageProcessor.Web.Caching
/// </returns> /// </returns>
public override async Task<bool> IsNewOrUpdatedAsync() public override async Task<bool> IsNewOrUpdatedAsync()
{ {
string cachedFileName = await this.CreateCachedFileName(); string cachedFileName = await this.CreateCachedFileNameAsync();
// Collision rate of about 1 in 10000 for the folder structure. // Collision rate of about 1 in 10000 for the folder structure.
// That gives us massive scope to store millions of files. // 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(@"\", "/"); this.virtualCachedFilePath = Path.Combine(this.virtualCachePath, virtualPathFromKey, cachedFileName).Replace(@"\", "/");
bool isUpdated = false; bool isUpdated = false;
CachedImage cachedImage = CacheIndexer.GetValue(this.CachedPath); CachedImage cachedImage = CacheIndexer.Get(this.CachedPath);
if (cachedImage == null) if (cachedImage == null)
{ {

8
src/ImageProcessor.Web/Caching/IImageCache.cs

@ -31,9 +31,9 @@ namespace ImageProcessor.Web.Caching
string CachedPath { get; } string CachedPath { get; }
/// <summary> /// <summary>
/// Gets the maximum number of days to store the image. /// Gets or sets the maximum number of days to store the image.
/// </summary> /// </summary>
int MaxDays { get; } int MaxDays { get; set; }
/// <summary> /// <summary>
/// Gets a value indicating whether the image is new or updated in an asynchronous manner. /// 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(); Task TrimCacheAsync();
/// <summary> /// <summary>
/// Gets a string identifying the cached file name. /// Gets a string identifying the cached file name in an asynchronous manner.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// The asynchronous <see cref="Task"/> returning the value. /// The asynchronous <see cref="Task"/> returning the value.
/// </returns> /// </returns>
Task<string> CreateCachedFileName(); Task<string> CreateCachedFileNameAsync();
/// <summary> /// <summary>
/// Rewrites the path to point to the cached image. /// Rewrites the path to point to the cached image.

9
src/ImageProcessor.Web/Caching/ImageCacheBase.cs

@ -61,6 +61,7 @@ namespace ImageProcessor.Web.Caching
this.FullPath = fullPath; this.FullPath = fullPath;
this.Querystring = querystring; this.Querystring = querystring;
this.Settings = ImageProcessorConfiguration.Instance.ImageCacheSettings; this.Settings = ImageProcessorConfiguration.Instance.ImageCacheSettings;
this.MaxDays = ImageProcessorConfiguration.Instance.ImageCacheMaxDays;
} }
/// <summary> /// <summary>
@ -74,9 +75,9 @@ namespace ImageProcessor.Web.Caching
public string CachedPath { get; set; } public string CachedPath { get; set; }
/// <summary> /// <summary>
/// Gets the maximum number of days to store the image. /// Gets or sets the maximum number of days to store the image.
/// </summary> /// </summary>
public abstract int MaxDays { get; } public int MaxDays { get; set; }
/// <summary> /// <summary>
/// Gets a value indicating whether the image is new or updated in an asynchronous manner. /// Gets a value indicating whether the image is new or updated in an asynchronous manner.
@ -114,7 +115,7 @@ namespace ImageProcessor.Web.Caching
/// <returns> /// <returns>
/// The asynchronous <see cref="Task"/> returning the value. /// The asynchronous <see cref="Task"/> returning the value.
/// </returns> /// </returns>
public virtual Task<string> CreateCachedFileName() public virtual async Task<string> CreateCachedFileNameAsync()
{ {
string streamHash = string.Empty; string streamHash = string.Empty;
@ -153,7 +154,7 @@ namespace ImageProcessor.Web.Caching
encryptedName, encryptedName,
!string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : "jpg"); !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : "jpg");
return Task.FromResult(cachedFileName); return await Task.FromResult(cachedFileName);
} }
/// <summary> /// <summary>

13
src/ImageProcessor.Web/Caching/MemCache.cs

@ -10,19 +10,16 @@
namespace ImageProcessor.Web.Caching namespace ImageProcessor.Web.Caching
{ {
#region Using
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.Caching; using System.Runtime.Caching;
#endregion
/// <summary> /// <summary>
/// Encapsulates methods that allow the caching and retrieval of objects from the in memory cache. /// Encapsulates methods that allow the caching and retrieval of objects from the in memory cache.
/// </summary> /// </summary>
internal static class MemCache internal static class MemCache
{ {
#region Fields
/// <summary> /// <summary>
/// The cache /// The cache
/// </summary> /// </summary>
@ -32,9 +29,7 @@ namespace ImageProcessor.Web.Caching
/// An internal list of cache keys to allow bulk removal. /// An internal list of cache keys to allow bulk removal.
/// </summary> /// </summary>
private static readonly ConcurrentDictionary<string, string> CacheItems = new ConcurrentDictionary<string, string>(); private static readonly ConcurrentDictionary<string, string> CacheItems = new ConcurrentDictionary<string, string>();
#endregion
#region Methods
/// <summary> /// <summary>
/// Adds an item to the cache. /// Adds an item to the cache.
/// </summary> /// </summary>
@ -105,7 +100,10 @@ namespace ImageProcessor.Web.Caching
/// </returns> /// </returns>
public static object GetItem(string key, string regionName = null) public static object GetItem(string key, string regionName = null)
{ {
return Cache.Get(key, regionName); lock (Cache)
{
return Cache.Get(key, regionName);
}
} }
/// <summary> /// <summary>
@ -131,7 +129,7 @@ namespace ImageProcessor.Web.Caching
/// True if the update try succeeds, or false if there is an already an entry /// True if the update try succeeds, or false if there is an already an entry
/// in the cache with the same key as key. /// in the cache with the same key as key.
/// </returns> /// </returns>
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; bool isUpDated = true;
@ -237,6 +235,5 @@ namespace ImageProcessor.Web.Caching
return isCleared; return isCleared;
} }
#endregion
} }
} }

20
src/ImageProcessor.Web/Configuration/ImageCacheSection.cs

@ -103,6 +103,26 @@ namespace ImageProcessor.Web.Configuration
set { this["type"] = value; } set { this["type"] = value; }
} }
/// <summary>
/// Gets or sets the maximum number of days to store an image in the cache.
/// </summary>
/// <value>The maximum number of days to store an image in the cache.</value>
/// <remarks>Defaults to 365 if not set.</remarks>
[ConfigurationProperty("maxDays", DefaultValue = "365", IsRequired = true)]
[IntegerValidator(ExcludeRange = false, MinValue = 0)]
public int MaxDays
{
get
{
return (int)this["maxDays"];
}
set
{
this["maxDays"] = value;
}
}
/// <summary> /// <summary>
/// Gets the <see cref="SettingElementCollection"/>. /// Gets the <see cref="SettingElementCollection"/>.
/// </summary> /// </summary>

6
src/ImageProcessor.Web/Configuration/ImageProcessingSection.cs

@ -23,8 +23,6 @@ namespace ImageProcessor.Web.Configuration
/// </summary> /// </summary>
public sealed class ImageProcessingSection : ConfigurationSection public sealed class ImageProcessingSection : ConfigurationSection
{ {
#region Properties
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to preserve exif meta data. /// Gets or sets a value indicating whether to preserve exif meta data.
/// </summary> /// </summary>
@ -69,9 +67,7 @@ namespace ImageProcessor.Web.Configuration
/// Gets or sets a value indicating whether to auto load plugins. /// Gets or sets a value indicating whether to auto load plugins.
/// </summary> /// </summary>
public bool AutoLoadPlugins { get; set; } public bool AutoLoadPlugins { get; set; }
#endregion
#region Methods
/// <summary> /// <summary>
/// Retrieves the processing configuration section from the current application configuration. /// Retrieves the processing configuration section from the current application configuration.
/// </summary> /// </summary>
@ -95,8 +91,6 @@ namespace ImageProcessor.Web.Configuration
return imageProcessingSection; return imageProcessingSection;
} }
#endregion
/// <summary> /// <summary>
/// Represents a PresetElement configuration element within the configuration. /// Represents a PresetElement configuration element within the configuration.
/// </summary> /// </summary>

7
src/ImageProcessor.Web/Configuration/ImageProcessorConfiguration.cs

@ -60,7 +60,6 @@ namespace ImageProcessor.Web.Configuration
#endregion #endregion
#region Constructors #region Constructors
/// <summary> /// <summary>
/// Prevents a default instance of the <see cref="ImageProcessorConfiguration"/> class from being created. /// Prevents a default instance of the <see cref="ImageProcessorConfiguration"/> class from being created.
/// </summary> /// </summary>
@ -99,6 +98,11 @@ namespace ImageProcessor.Web.Configuration
/// </summary> /// </summary>
public Type ImageCache { get; private set; } public Type ImageCache { get; private set; }
/// <summary>
/// Gets the image cache max days.
/// </summary>
public int ImageCacheMaxDays { get; private set; }
/// <summary> /// <summary>
/// Gets the image cache settings. /// Gets the image cache settings.
/// </summary> /// </summary>
@ -435,6 +439,7 @@ namespace ImageProcessor.Web.Configuration
} }
this.ImageCache = type; this.ImageCache = type;
this.ImageCacheMaxDays = cache.MaxDays;
this.ImageCacheSettings = cache.Settings this.ImageCacheSettings = cache.Settings
.Cast<SettingElement>() .Cast<SettingElement>()
.ToDictionary(setting => setting.Key, setting => setting.Value); .ToDictionary(setting => setting.Key, setting => setting.Value);

3
src/ImageProcessor.Web/Configuration/Resources/cache.config.transform

@ -1,8 +1,7 @@
<caching currentCache="DiskCache"> <caching currentCache="DiskCache">
<caches> <caches>
<cache name="DiskCache" type="ImageProcessor.Web.Caching.DiskCache, ImageProcessor.Web"> <cache name="DiskCache" type="ImageProcessor.Web.Caching.DiskCache, ImageProcessor.Web" maxDays="365">
<settings> <settings>
<setting key="MaxDays" value="365"/>
<setting key="VirtualCachePath" value="~/app_data/cache"/> <setting key="VirtualCachePath" value="~/app_data/cache"/>
</settings> </settings>
</cache> </cache>

2
src/ImageProcessor.Web/Helpers/RemoteFile.cs

@ -10,7 +10,6 @@
namespace ImageProcessor.Web.Helpers namespace ImageProcessor.Web.Helpers
{ {
#region Using
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@ -18,7 +17,6 @@ namespace ImageProcessor.Web.Helpers
using System.Security; using System.Security;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
#endregion
/// <summary> /// <summary>
/// Encapsulates methods used to download files from a website address. /// Encapsulates methods used to download files from a website address.

16
src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs

@ -470,15 +470,15 @@ namespace ImageProcessor.Web.HttpModules
/// </param> /// </param>
private void SetHeaders(HttpContext context, string responseType, IEnumerable<string> dependencyPaths) private void SetHeaders(HttpContext context, string responseType, IEnumerable<string> dependencyPaths)
{ {
HttpResponse response = context.Response;
if (response.Headers["Image-Served-By"] == null)
{
response.AddHeader("Image-Served-By", "ImageProcessor.Web/" + AssemblyVersion);
}
if (this.imageCache != null) if (this.imageCache != null)
{ {
HttpResponse response = context.Response;
if (response.Headers["ImageProcessedBy"] == null)
{
response.AddHeader("ImageProcessedBy", "ImageProcessor.Web/" + AssemblyVersion);
}
HttpCachePolicy cache = response.Cache; HttpCachePolicy cache = response.Cache;
cache.SetCacheability(HttpCacheability.Public); cache.SetCacheability(HttpCacheability.Public);
cache.VaryByHeaders["Accept-Encoding"] = true; cache.VaryByHeaders["Accept-Encoding"] = true;
@ -499,6 +499,8 @@ namespace ImageProcessor.Web.HttpModules
cache.SetExpires(DateTime.Now.ToUniversalTime().AddDays(maxDays)); cache.SetExpires(DateTime.Now.ToUniversalTime().AddDays(maxDays));
cache.SetMaxAge(new TimeSpan(maxDays, 0, 0, 0)); cache.SetMaxAge(new TimeSpan(maxDays, 0, 0, 0));
cache.SetRevalidation(HttpCacheRevalidation.AllCaches); cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
this.imageCache = null;
} }
} }

6
src/TestWebsites/MVC/Views/Home/External.cshtml

@ -5,15 +5,15 @@
<section> <section>
<div class="row"> <div class="row">
<div class="col-s-6"> <div class="col-s-6">
<img src="/remote.axd?http://images.mymovies.net/images/film/cin/500x377/fid11707.jpg?width=400" /> <img src="/remote.axd?http://images.mymovies.net/images/film/cin/500x377/fid11707.jpg?width=399" />
</div> </div>
<div class="col-s-6"> <div class="col-s-6">
<img src="/remote.axd?http://maps.googleapis.com/maps/api/staticmap?center=Albany,+NY&zoom=13&scale=false&size=800x500&maptype=roadmap&sensor=false&format=png&visual_refresh=true?width=400" /> <img src="/remote.axd?http://maps.googleapis.com/maps/api/staticmap?center=Albany,+NY&zoom=13&scale=false&size=800x500&maptype=roadmap&sensor=false&format=png&visual_refresh=true?width=401" />
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-s-6"> <div class="col-s-6">
<img src="/remote.axd?http://images.hanselminutes.com/images/255.jpg?width=200" /> <img src="/remote.axd?http://images.hanselminutes.com/images/255.jpg?width=201" />
</div> </div>
</div> </div>
</section> </section>

4
src/TestWebsites/MVC/config/imageprocessor/cache.config

@ -1,11 +1,9 @@
<caching currentCache="DiskCache"> <caching currentCache="DiskCache">
<caches> <caches>
<cache name="DiskCache" type="ImageProcessor.Web.Caching.DiskCache, ImageProcessor.Web"> <cache name="DiskCache" type="ImageProcessor.Web.Caching.DiskCache, ImageProcessor.Web" maxDays="365">
<settings> <settings>
<setting key="MaxDays" value="56"/>
<setting key="VirtualCachePath" value="~/app_data/cache"/> <setting key="VirtualCachePath" value="~/app_data/cache"/>
</settings> </settings>
</cache> </cache>
</caches> </caches>
</caching> </caching>

Loading…
Cancel
Save