diff --git a/src/ImageProcessor.Web/Caching/DiskCache.cs b/src/ImageProcessor.Web/Caching/DiskCache.cs
index 8fb69810b..c0ebbe2bc 100644
--- a/src/ImageProcessor.Web/Caching/DiskCache.cs
+++ b/src/ImageProcessor.Web/Caching/DiskCache.cs
@@ -16,7 +16,6 @@ namespace ImageProcessor.Web.Caching
using System.Globalization;
using System.IO;
using System.Linq;
- using System.Threading.Tasks;
using System.Web.Hosting;
using ImageProcessor.Web.Configuration;
@@ -130,14 +129,65 @@ namespace ImageProcessor.Web.Caching
}
#region Methods
- #region Internal
+ #region Public
+ ///
+ /// Trims a cached folder ensuring that it does not exceed the maximum file count.
+ ///
+ ///
+ /// The path to the folder.
+ ///
+ public static void TrimCachedFolders(string path)
+ {
+ string directory = Path.GetDirectoryName(path);
+
+ if (directory != null)
+ {
+ DirectoryInfo directoryInfo = new DirectoryInfo(directory);
+ DirectoryInfo parentDirectoryInfo = directoryInfo.Parent;
+
+ if (parentDirectoryInfo != null)
+ {
+ // UNC folders can throw exceptions if the file doesn't exist.
+ foreach (DirectoryInfo enumerateDirectory in parentDirectoryInfo.SafeEnumerateDirectories())
+ {
+ IEnumerable files = enumerateDirectory.EnumerateFiles().OrderBy(f => f.CreationTimeUtc);
+ int count = files.Count();
+
+ foreach (FileInfo fileInfo in files)
+ {
+ try
+ {
+ // If the group count is equal to the max count minus 1 then we know we
+ // have reduced the number of items below the maximum allowed.
+ // We'll cleanup any orphaned expired files though.
+ if (!IsExpired(fileInfo.CreationTimeUtc) && count <= MaxFilesCount - 1)
+ {
+ break;
+ }
+
+ // Remove from the cache and delete each CachedImage.
+ CacheIndexer.Remove(fileInfo.Name);
+ fileInfo.Delete();
+ count -= 1;
+ }
+ // ReSharper disable once EmptyGeneralCatchClause
+ catch
+ {
+ // Do nothing; skip to the next file.
+ }
+ }
+ }
+ }
+ }
+ }
+
///
/// Adds an image to the cache.
///
///
/// The path to the cached image.
///
- internal void AddImageToCache(string cachedPath)
+ public void AddImageToCache(string cachedPath)
{
string key = Path.GetFileNameWithoutExtension(cachedPath);
CachedImage cachedImage = new CachedImage
@@ -159,7 +209,7 @@ namespace ImageProcessor.Web.Caching
///
/// True if the the original file is new or has been updated; otherwise, false.
///
- internal bool IsNewOrUpdatedFile(string cachedPath)
+ public bool IsNewOrUpdatedFile(string cachedPath)
{
bool isUpdated = false;
CachedImage cachedImage = CacheIndexer.GetValue(cachedPath);
@@ -172,7 +222,7 @@ namespace ImageProcessor.Web.Caching
else
{
// Check to see if the cached image is set to expire.
- if (this.IsExpired(cachedImage.CreationTimeUtc))
+ if (IsExpired(cachedImage.CreationTimeUtc))
{
CacheIndexer.Remove(cachedPath);
isUpdated = true;
@@ -181,72 +231,22 @@ namespace ImageProcessor.Web.Caching
return isUpdated;
}
-
- ///
- /// Trims a cached folder ensuring that it does not exceed the maximum file count.
- ///
- ///
- /// The path to the folder.
- ///
- ///
- /// The .
- ///
- internal async Task TrimCachedFolderAsync(string path)
- {
- await Task.Run(() => this.TrimCachedFolders(path));
- }
#endregion
#region Private
///
- /// Trims a cached folder ensuring that it does not exceed the maximum file count.
+ /// Gets a value indicating whether the given images creation date is out with
+ /// the prescribed limit.
///
- ///
- /// The path to the folder.
+ ///
+ /// The creation date.
///
- private void TrimCachedFolders(string path)
+ ///
+ /// The true if the date is out with the limit, otherwise; false.
+ ///
+ private static bool IsExpired(DateTime creationDate)
{
- string directory = Path.GetDirectoryName(path);
-
- if (directory != null)
- {
- DirectoryInfo directoryInfo = new DirectoryInfo(directory);
- DirectoryInfo parentDirectoryInfo = directoryInfo.Parent;
-
- if (parentDirectoryInfo != null)
- {
- // UNC folders can throw exceptions if the file doesn't exist.
- foreach (DirectoryInfo enumerateDirectory in parentDirectoryInfo.SafeEnumerateDirectories())
- {
- IEnumerable files = enumerateDirectory.EnumerateFiles().OrderBy(f => f.CreationTimeUtc);
- int count = files.Count();
-
- foreach (FileInfo fileInfo in files)
- {
- try
- {
- // If the group count is equal to the max count minus 1 then we know we
- // have reduced the number of items below the maximum allowed.
- // We'll cleanup any orphaned expired files though.
- if (!this.IsExpired(fileInfo.CreationTimeUtc) && count <= MaxFilesCount - 1)
- {
- break;
- }
-
- // Remove from the cache and delete each CachedImage.
- CacheIndexer.Remove(fileInfo.Name);
- fileInfo.Delete();
- count -= 1;
- }
- // ReSharper disable once EmptyGeneralCatchClause
- catch
- {
- // Do nothing; skip to the next file.
- }
- }
- }
- }
- }
+ return creationDate.AddDays(MaxFileCachedDuration) < DateTime.UtcNow.AddDays(-MaxFileCachedDuration);
}
///
@@ -305,21 +305,6 @@ namespace ImageProcessor.Web.Caching
this.virtualCachedPath = Path.Combine(VirtualCachePath, virtualPathFromKey, cachedFileName).Replace(@"\", "/");
}
}
-
- ///
- /// 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.
- ///
- private bool IsExpired(DateTime creationDate)
- {
- return creationDate.AddDays(MaxFileCachedDuration) < DateTime.UtcNow.AddDays(-MaxFileCachedDuration);
- }
#endregion
#endregion
}
diff --git a/src/ImageProcessor.Web/Helpers/RemoteFile.cs b/src/ImageProcessor.Web/Helpers/RemoteFile.cs
index 6845d8453..679157dc1 100644
--- a/src/ImageProcessor.Web/Helpers/RemoteFile.cs
+++ b/src/ImageProcessor.Web/Helpers/RemoteFile.cs
@@ -13,12 +13,15 @@ namespace ImageProcessor.Web.Helpers
#region Using
using System;
using System.Collections.Generic;
+ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Security;
using System.Text;
using System.Threading.Tasks;
+ using System.Web;
+
using ImageProcessor.Web.Configuration;
#endregion
@@ -241,27 +244,43 @@ namespace ImageProcessor.Web.Helpers
///
internal async Task GetWebResponseAsync()
{
- WebResponse response = await this.GetWebRequest().GetResponseAsync();
+ WebResponse response = null;
+ try
+ {
+ response = await this.GetWebRequest().GetResponseAsync();
+ }
+ catch (WebException ex)
+ {
+ if (ex.Status == WebExceptionStatus.NameResolutionFailure)
+ {
+ throw new HttpException(404, "No image exists at " + Uri);
+ }
- long contentLength = response.ContentLength;
+ throw;
+ }
- // WebResponse.ContentLength doesn't always know the value, it returns -1 in this case.
- if (contentLength == -1)
+ if (response != null)
{
- // Response headers may still have the Content-Length inside of it.
- string headerContentLength = response.Headers["Content-Length"];
+ long contentLength = response.ContentLength;
- if (!string.IsNullOrWhiteSpace(headerContentLength))
+ // WebResponse.ContentLength doesn't always know the value, it returns -1 in this case.
+ if (contentLength == -1)
{
- contentLength = long.Parse(headerContentLength, CultureInfo.InvariantCulture);
+ // Response headers may still have the Content-Length inside of it.
+ string headerContentLength = response.Headers["Content-Length"];
+
+ if (!string.IsNullOrWhiteSpace(headerContentLength))
+ {
+ contentLength = long.Parse(headerContentLength, CultureInfo.InvariantCulture);
+ }
}
- }
- // We don't need to check the url here since any external urls are available only from the web.config.
- if ((this.MaxDownloadSize > 0) && (contentLength > this.MaxDownloadSize))
- {
- response.Close();
- throw new SecurityException("An attempt to download a remote file has been halted because the file is larger than allowed.");
+ // We don't need to check the url here since any external urls are available only from the web.config.
+ if ((this.MaxDownloadSize > 0) && (contentLength > this.MaxDownloadSize))
+ {
+ response.Close();
+ throw new SecurityException("An attempt to download a remote file has been halted because the file is larger than allowed.");
+ }
}
return response;
diff --git a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs
index e9eeb56ab..81372f5c8 100644
--- a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs
+++ b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs
@@ -225,6 +225,9 @@ namespace ImageProcessor.Web.HttpModules
{
string cachedPath = cachedPathObject.ToString();
+ // Trim the cache.
+ DiskCache.TrimCachedFolders(cachedPath);
+
// Fire the post processing event.
EventHandler handler = OnPostProcessing;
if (handler != null)
@@ -347,7 +350,7 @@ namespace ImageProcessor.Web.HttpModules
{
string hashedUrlParameters = urlParameters.ToMD5Fingerprint();
- // TODO: Add hash for querystring parameters.
+ // TODO: Add hash for querystring parameters?
imageName += hashedUrlParameters;
fullPath += hashedUrlParameters;
}
@@ -425,9 +428,6 @@ namespace ImageProcessor.Web.HttpModules
// Add to the cache.
cache.AddImageToCache(cachedPath);
- // Trim the cache.
- await cache.TrimCachedFolderAsync(cachedPath);
-
// Store the cached path, response type, and cache dependency in the context for later retrieval.
context.Items[CachedPathKey] = cachedPath;
context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType;
@@ -440,7 +440,7 @@ namespace ImageProcessor.Web.HttpModules
}
else
{
- using (await Locker.LockAsync(cachedPath))
+ using (Locker.Lock(cachedPath))
{
// Check to see if the file exists.
// ReSharper disable once AssignNullToNotNullAttribute
@@ -459,9 +459,6 @@ namespace ImageProcessor.Web.HttpModules
// Add to the cache.
cache.AddImageToCache(cachedPath);
- // Trim the cache.
- await cache.TrimCachedFolderAsync(cachedPath);
-
// Store the cached path, response type, and cache dependencies in the context for later retrieval.
context.Items[CachedPathKey] = cachedPath;
context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType;
diff --git a/src/ImageProcessor/Configuration/NativeMethods.cs b/src/ImageProcessor/Configuration/NativeMethods.cs
index 6c1ab9805..895de7fe5 100644
--- a/src/ImageProcessor/Configuration/NativeMethods.cs
+++ b/src/ImageProcessor/Configuration/NativeMethods.cs
@@ -27,7 +27,7 @@ namespace ImageProcessor.Configuration
/// an executable module.
///
/// If the function succeeds, the return value is a handle to the module; otherwise null.
- [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
+ [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr LoadLibrary(string libname);
///
@@ -38,7 +38,7 @@ namespace ImageProcessor.Configuration
/// A handle to the loaded library module.
/// The LoadLibrary, LoadLibraryEx, GetModuleHandle, or GetModuleHandleEx function returns this handle.
/// If the function succeeds, the return value is nonzero; otherwise zero.
- [DllImport("kernel32", CharSet = CharSet.Auto)]
+ [DllImport("kernel32", SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);
///
diff --git a/src/TestWebsites/MVC/Web.config b/src/TestWebsites/MVC/Web.config
index 3b4f02f51..e2f38f0a4 100644
--- a/src/TestWebsites/MVC/Web.config
+++ b/src/TestWebsites/MVC/Web.config
@@ -28,7 +28,7 @@
-
+