From 6d76e72a790935c331ed6158c3ec10b704a608a1 Mon Sep 17 00:00:00 2001 From: JimBobSquarePants Date: Thu, 21 Mar 2013 01:00:19 +0000 Subject: [PATCH] 2.0.1.0 Former-commit-id: 1decdd0c6f5a5cc4b794bc37f4a4c3c5d023fd24 --- .../Caching/PersistantDictionary.cs | 3 + .../{Caching => Helpers}/LockedDictionary.cs | 2 +- .../HttpModules/ImageProcessingModule.cs | 133 +++++++----------- .../ImageProcessor.Web.csproj | 2 +- .../Properties/AssemblyInfo.cs | 4 +- src/Nuget/ImageProcessor.Web.2.0.1.0.nupkg | Bin 0 -> 20467 bytes 6 files changed, 54 insertions(+), 90 deletions(-) rename src/ImageProcessor.Web/{Caching => Helpers}/LockedDictionary.cs (99%) create mode 100644 src/Nuget/ImageProcessor.Web.2.0.1.0.nupkg diff --git a/src/ImageProcessor.Web/Caching/PersistantDictionary.cs b/src/ImageProcessor.Web/Caching/PersistantDictionary.cs index 81f79c669..f20efdf82 100644 --- a/src/ImageProcessor.Web/Caching/PersistantDictionary.cs +++ b/src/ImageProcessor.Web/Caching/PersistantDictionary.cs @@ -10,6 +10,9 @@ namespace ImageProcessor.Web.Caching #region Using using System; using System.Collections.Generic; + + using ImageProcessor.Web.Helpers; + #endregion /// diff --git a/src/ImageProcessor.Web/Caching/LockedDictionary.cs b/src/ImageProcessor.Web/Helpers/LockedDictionary.cs similarity index 99% rename from src/ImageProcessor.Web/Caching/LockedDictionary.cs rename to src/ImageProcessor.Web/Helpers/LockedDictionary.cs index afa4edab4..3f41d25cc 100644 --- a/src/ImageProcessor.Web/Caching/LockedDictionary.cs +++ b/src/ImageProcessor.Web/Helpers/LockedDictionary.cs @@ -5,7 +5,7 @@ // // ----------------------------------------------------------------------- -namespace ImageProcessor.Web.Caching +namespace ImageProcessor.Web.Helpers { #region Using using System.Collections.Generic; diff --git a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs index a1b968cd8..409181289 100644 --- a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs @@ -19,9 +19,6 @@ namespace ImageProcessor.Web.HttpModules using ImageProcessor.Web.Caching; using ImageProcessor.Web.Config; using ImageProcessor.Web.Helpers; - using System.Collections.Concurrent; - using System.Threading.Tasks; - using System.Threading; #endregion /// @@ -51,15 +48,19 @@ namespace ImageProcessor.Web.HttpModules private static readonly string AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); /// - /// The thread safe fifo queue. + /// A value indicating whether the application has started. /// - private static ConcurrentQueue imageOperations; + private static bool hasModuleInitialized; + #endregion /// - /// A value indicating whether the application has started. + /// The delegate void representing the ProcessImage method. /// - private static bool hasAppStarted = false; - #endregion + /// + /// the HttpContext object that provides + /// references to the intrinsic server objects + /// + private delegate void ProcessImageDelegate(HttpContext context); #region IHttpModule Members /// @@ -72,23 +73,20 @@ namespace ImageProcessor.Web.HttpModules /// public void Init(HttpApplication context) { - if (!hasAppStarted) + if (!hasModuleInitialized) { lock (SyncRoot) { - if (!hasAppStarted) + if (!hasModuleInitialized) { - imageOperations = new ConcurrentQueue(); DiskCache.CreateCacheDirectories(); - hasAppStarted = true; + hasModuleInitialized = true; } } } - context.AddOnBeginRequestAsync(OnBeginAsync, OnEndAsync); - //context.BeginRequest += this.ContextBeginRequest; + context.AddOnBeginRequestAsync(this.OnBeginAsync, this.OnEndAsync); context.PreSendRequestHeaders += this.ContextPreSendRequestHeaders; - } /// @@ -102,28 +100,30 @@ namespace ImageProcessor.Web.HttpModules /// /// The that starts asynchronous processing - /// of the . + /// of the . /// /// The source of the event. /// /// An EventArgs that contains /// the event data. /// - /// + /// /// The delegate to call when the asynchronous method call is complete. - /// If cb is null, the delegate is not called. + /// If the callback is null, the delegate is not called. /// - /// + /// /// Any additional data needed to process the request. /// - /// - IAsyncResult OnBeginAsync(object sender, EventArgs e, AsyncCallback cb, object extraData) + /// + /// The status of the asynchronous operation. + /// + private IAsyncResult OnBeginAsync(object sender, EventArgs e, AsyncCallback callBack, object state) { HttpContext context = ((HttpApplication)sender).Context; - EnqueueDelegate enqueueDelegate = new EnqueueDelegate(Enqueue); - return enqueueDelegate.BeginInvoke(context, cb, extraData); + ProcessImageDelegate processImage = this.ProcessImage; + return processImage.BeginInvoke(context, callBack, state); } /// @@ -133,53 +133,13 @@ namespace ImageProcessor.Web.HttpModules /// The that is the result of the /// operation. /// - public void OnEndAsync(IAsyncResult result) + private void OnEndAsync(IAsyncResult result) { - // An action to consume the ConcurrentQueue. - Action action = () => + // Ensure our ProcessImage has completed in the background. + while (!result.IsCompleted) { - Action op; - - while (imageOperations.TryDequeue(out op)) - { - op(); - } - }; - - // Start 4 concurrent consuming actions. - Parallel.Invoke(action, action, action, action); - } - - /// - /// The delegate void representing the Enqueue method. - /// - /// - /// the HttpContext object that provides - /// references to the intrinsic server objects - /// - private delegate void EnqueueDelegate(HttpContext context); - - /// - /// Adds the method to the queue. - /// - /// - /// the HttpContext object that provides - /// references to the intrinsic server objects - /// - private void Enqueue(HttpContext context) - { - imageOperations.Enqueue(() => ProcessImage(context)); - } - - /// - /// Occurs as the first event in the HTTP pipeline chain of execution when ASP.NET responds to a request. - /// - /// The source of the event. - /// An EventArgs that contains the event data. - private void ContextBeginRequest(object sender, EventArgs e) - { - HttpContext context = ((HttpApplication)sender).Context; - imageOperations.Enqueue(() => ProcessImage(context)); + System.Threading.Thread.Sleep(1); + } } /// @@ -197,6 +157,7 @@ namespace ImageProcessor.Web.HttpModules { string responseType = (string)responseTypeObject; + // Set the headers this.SetHeaders(context, responseType); context.Items[CachedResponseTypeKey] = null; @@ -270,21 +231,21 @@ namespace ImageProcessor.Web.HttpModules { //lock (SyncRoot) //{ - // Trim the cache. - DiskCache.TrimCachedFolders(); + // Trim the cache. + DiskCache.TrimCachedFolders(); - responseStream.CopyTo(memoryStream); + responseStream.CopyTo(memoryStream); - imageFactory.Load(memoryStream) - .AddQueryString(queryString) - .Format(ImageUtils.GetImageFormat(imageName)) - .AutoProcess().Save(cachedPath); + imageFactory.Load(memoryStream) + .AddQueryString(queryString) + .Format(ImageUtils.GetImageFormat(imageName)) + .AutoProcess().Save(cachedPath); - // Ensure that the LastWriteTime property of the source and cached file match. - DateTime dateTime = DiskCache.SetCachedLastWriteTime(path, cachedPath, true); + // Ensure that the LastWriteTime property of the source and cached file match. + DateTime dateTime = DiskCache.SetCachedLastWriteTime(path, cachedPath, true); - // Add to the cache. - DiskCache.AddImageToCache(cachedPath, dateTime); + // Add to the cache. + DiskCache.AddImageToCache(cachedPath, dateTime); //} } } @@ -294,16 +255,16 @@ namespace ImageProcessor.Web.HttpModules { //lock (SyncRoot) //{ - // Trim the cache. - DiskCache.TrimCachedFolders(); + // Trim the cache. + DiskCache.TrimCachedFolders(); - imageFactory.Load(fullPath).AutoProcess().Save(cachedPath); + imageFactory.Load(fullPath).AutoProcess().Save(cachedPath); - // Ensure that the LastWriteTime property of the source and cached file match. - DateTime dateTime = DiskCache.SetCachedLastWriteTime(path, cachedPath, false); + // Ensure that the LastWriteTime property of the source and cached file match. + DateTime dateTime = DiskCache.SetCachedLastWriteTime(path, cachedPath, false); - // Add to the cache. - DiskCache.AddImageToCache(cachedPath, dateTime); + // Add to the cache. + DiskCache.AddImageToCache(cachedPath, dateTime); //} } } diff --git a/src/ImageProcessor.Web/ImageProcessor.Web.csproj b/src/ImageProcessor.Web/ImageProcessor.Web.csproj index 405a17081..0ab6f04c4 100644 --- a/src/ImageProcessor.Web/ImageProcessor.Web.csproj +++ b/src/ImageProcessor.Web/ImageProcessor.Web.csproj @@ -88,7 +88,7 @@ - + diff --git a/src/ImageProcessor.Web/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs index a2f13edc1..7ecd2ad29 100644 --- a/src/ImageProcessor.Web/Properties/AssemblyInfo.cs +++ b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.0.0")] -[assembly: AssemblyFileVersion("2.0.0.0")] +[assembly: AssemblyVersion("2.0.1.0")] +[assembly: AssemblyFileVersion("2.0.1.0")] diff --git a/src/Nuget/ImageProcessor.Web.2.0.1.0.nupkg b/src/Nuget/ImageProcessor.Web.2.0.1.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..cbd19db4a2a54b890a019267708c88fcc20f13df GIT binary patch literal 20467 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 JcyIF8zX529RtW$A literal 0 HcmV?d00001