Browse Source

Adding code comments

Former-commit-id: 2a51566a5c79a24bda73701a439d91b1492b0f59
Former-commit-id: 2d4fff12db92bc6a959fb94a5f2b3a4e551fe0f0
af/merge-core
James South 11 years ago
parent
commit
be7f51318e
  1. 115
      src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs
  2. 55
      src/ImageProcessor.Web/Caching/DiskCache.cs
  3. 58
      src/ImageProcessor.Web/Caching/IImageCache.cs
  4. 62
      src/ImageProcessor.Web/Caching/ImageCacheBase.cs
  5. 4
      src/ImageProcessor.Web/Services/IImageService.cs
  6. 1
      src/ImageProcessor.Web/Settings.StyleCop

115
src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs

@ -1,4 +1,15 @@
namespace ImageProcessor.Web.Caching // --------------------------------------------------------------------------------------------------------------------
// <copyright file="AzureBlobCache.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Provides an <see cref="IImageCache" /> implementation that uses Azure blob storage.
// The cache is self healing and cleaning.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Web.Caching
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -15,54 +26,72 @@
using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob; using Microsoft.WindowsAzure.Storage.Blob;
/// <summary>
/// Provides an <see cref="IImageCache"/> implementation that uses Azure blob storage.
/// The cache is self healing and cleaning.
/// </summary>
public class AzureBlobCache : ImageCacheBase public class AzureBlobCache : ImageCacheBase
{ {
/// <summary> /// <summary>
/// The max age. /// The maximum number of days to store the image.
/// </summary> /// </summary>
private readonly int maxDays; private readonly int maxDays;
private CloudStorageAccount cloudCachedStorageAccount; /// <summary>
/// The cloud cached blob container.
private CloudStorageAccount cloudSourceStorageAccount; /// </summary>
private readonly CloudBlobContainer cloudCachedBlobContainer;
private CloudBlobClient cloudCachedBlobClient;
private CloudBlobClient cloudSourceBlobClient;
private CloudBlobContainer cloudCachedBlobContainer;
private CloudBlobContainer cloudSourceBlobContainer; /// <summary>
/// The cloud source blob container.
/// </summary>
private readonly CloudBlobContainer cloudSourceBlobContainer;
private string cachedCDNRoot; /// <summary>
/// The cached root url for a content delivery network.
/// </summary>
private readonly string cachedCdnRoot;
/// <summary>
/// The cached rewrite path.
/// </summary>
private string cachedRewritePath; private string cachedRewritePath;
/// <summary> /// <summary>
/// The physical cached path. /// Initializes a new instance of the <see cref="AzureBlobCache"/> class.
/// </summary> /// </summary>
private string physicalCachedPath; /// <param name="requestPath">
/// The request path for the image.
/// </param>
/// <param name="fullPath">
/// The full path for the image.
/// </param>
/// <param name="querystring">
/// The querystring containing instructions.
/// </param>
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"]); this.maxDays = Convert.ToInt32(this.Settings["MaxDays"]);
// Retrieve storage accounts from connection string. // Retrieve storage accounts from connection string.
this.cloudCachedStorageAccount = CloudStorageAccount.Parse(this.Settings["CachedStorageAccount"]); CloudStorageAccount cloudCachedStorageAccount = CloudStorageAccount.Parse(this.Settings["CachedStorageAccount"]);
this.cloudSourceStorageAccount = CloudStorageAccount.Parse(this.Settings["SourceStorageAccount"]); CloudStorageAccount cloudSourceStorageAccount = CloudStorageAccount.Parse(this.Settings["SourceStorageAccount"]);
// Create the blob clients. // Create the blob clients.
this.cloudCachedBlobClient = this.cloudCachedStorageAccount.CreateCloudBlobClient(); CloudBlobClient cloudCachedBlobClient = cloudCachedStorageAccount.CreateCloudBlobClient();
this.cloudSourceBlobClient = this.cloudSourceStorageAccount.CreateCloudBlobClient(); CloudBlobClient cloudSourceBlobClient = cloudSourceStorageAccount.CreateCloudBlobClient();
// Retrieve references to a previously created containers. // Retrieve references to a previously created containers.
this.cloudCachedBlobContainer = this.cloudCachedBlobClient.GetContainerReference(this.Settings["CachedBlobContainer"]); this.cloudCachedBlobContainer = cloudCachedBlobClient.GetContainerReference(this.Settings["CachedBlobContainer"]);
this.cloudSourceBlobContainer = this.cloudSourceBlobClient.GetContainerReference(this.Settings["SourceBlobContainer"]); this.cloudSourceBlobContainer = cloudSourceBlobClient.GetContainerReference(this.Settings["SourceBlobContainer"]);
this.cachedCDNRoot = this.Settings["CachedCDNRoot"]; this.cachedCdnRoot = this.Settings["CachedCDNRoot"];
} }
/// <summary>
/// Gets the maximum number of days to store the image.
/// </summary>
public override int MaxDays public override int MaxDays
{ {
get get
@ -71,6 +100,12 @@
} }
} }
/// <summary>
/// Gets a value indicating whether the image is new or updated in an asynchronous manner.
/// </summary>
/// <returns>
/// The asynchronous <see cref="Task"/> returning the value.
/// </returns>
public override async Task<bool> IsNewOrUpdatedAsync() public override async Task<bool> IsNewOrUpdatedAsync()
{ {
string cachedFileName = await this.CreateCachedFileName(); string cachedFileName = await this.CreateCachedFileName();
@ -79,7 +114,7 @@
// That gives us massive scope to store millions of files. // That gives us massive scope to store millions of files.
string pathFromKey = string.Join("\\", cachedFileName.ToCharArray().Take(6)); string pathFromKey = string.Join("\\", cachedFileName.ToCharArray().Take(6));
this.CachedPath = Path.Combine(this.cloudCachedBlobContainer.Uri.ToString(), pathFromKey, cachedFileName).Replace(@"\", "/"); 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; bool isUpdated = false;
CachedImage cachedImage = CacheIndexer.GetValue(this.CachedPath); CachedImage cachedImage = CacheIndexer.GetValue(this.CachedPath);
@ -147,18 +182,36 @@
return isUpdated; return isUpdated;
} }
/// <summary>
/// Adds the image to the cache in an asynchronous manner.
/// </summary>
/// <param name="stream">
/// The stream containing the image data.
/// </param>
/// <param name="contentType">
/// The content type of the image.
/// </param>
/// <returns>
/// The <see cref="Task"/> representing an asynchronous operation.
/// </returns>
public override async Task AddImageToCacheAsync(Stream stream, string contentType) public override async Task AddImageToCacheAsync(Stream stream, string contentType)
{ {
string blobPath = this.CachedPath.Substring(this.cloudCachedBlobContainer.Uri.ToString().Length + 1); string blobPath = this.CachedPath.Substring(this.cloudCachedBlobContainer.Uri.ToString().Length + 1);
CloudBlockBlob blockBlob = this.cloudCachedBlobContainer.GetBlockBlobReference(blobPath); CloudBlockBlob blockBlob = this.cloudCachedBlobContainer.GetBlockBlobReference(blobPath);
await blockBlob.UploadFromStreamAsync(stream); await blockBlob.UploadFromStreamAsync(stream);
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();
} }
/// <summary>
/// Trims the cache of any expired items in an asynchronous manner.
/// </summary>
/// <returns>
/// The asynchronous <see cref="Task"/> representing an asynchronous operation.
/// </returns>
public override async Task TrimCacheAsync() public override async Task TrimCacheAsync()
{ {
Uri uri = new Uri(this.CachedPath); Uri uri = new Uri(this.CachedPath);
@ -197,6 +250,12 @@
} }
} }
/// <summary>
/// Gets a string identifying the cached file name.
/// </summary>
/// <returns>
/// The asynchronous <see cref="Task"/> returning the value.
/// </returns>
public override async Task<string> CreateCachedFileName() public override async Task<string> CreateCachedFileName()
{ {
string streamHash = string.Empty; string streamHash = string.Empty;
@ -260,6 +319,12 @@
return cachedFileName; return cachedFileName;
} }
/// <summary>
/// Rewrites the path to point to the cached image.
/// </summary>
/// <param name="context">
/// The <see cref="HttpContext"/> encapsulating all information about the request.
/// </param>
public override void RewritePath(HttpContext context) public override void RewritePath(HttpContext context)
{ {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.cachedRewritePath); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.cachedRewritePath);

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

@ -1,4 +1,15 @@
namespace ImageProcessor.Web.Caching // --------------------------------------------------------------------------------------------------------------------
// <copyright file="DiskCache.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Provides an <see cref="IImageCache" /> implementation that is file system based.
// The cache is self healing and cleaning.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Web.Caching
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -9,9 +20,12 @@
using System.Web; using System.Web;
using System.Web.Hosting; using System.Web.Hosting;
using ImageProcessor.Web.Configuration;
using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Extensions;
/// <summary>
/// Provides an <see cref="IImageCache"/> implementation that is file system based.
/// The cache is self healing and cleaning.
/// </summary>
public class DiskCache : ImageCacheBase public class DiskCache : ImageCacheBase
{ {
/// <summary> /// <summary>
@ -27,7 +41,7 @@
private const int MaxFilesCount = 100; private const int MaxFilesCount = 100;
/// <summary> /// <summary>
/// The max age. /// The maximum number of days to store the image.
/// </summary> /// </summary>
private readonly int maxDays; private readonly int maxDays;
@ -42,7 +56,7 @@
private readonly string absoluteCachePath; private readonly string absoluteCachePath;
/// <summary> /// <summary>
/// The virtual cached path to the cached file. /// The virtual path to the cached file.
/// </summary> /// </summary>
private string virtualCachedFilePath; private string virtualCachedFilePath;
@ -75,8 +89,7 @@
} }
/// <summary> /// <summary>
/// The maximum number of days to cache files on the system for. /// Gets the maximum number of days to store the image.
/// TODO: Shift the getter source to proper config.
/// </summary> /// </summary>
public override int MaxDays public override int MaxDays
{ {
@ -86,6 +99,12 @@
} }
} }
/// <summary>
/// Gets a value indicating whether the image is new or updated in an asynchronous manner.
/// </summary>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public override async Task<bool> IsNewOrUpdatedAsync() public override async Task<bool> IsNewOrUpdatedAsync()
{ {
string cachedFileName = await this.CreateCachedFileName(); string cachedFileName = await this.CreateCachedFileName();
@ -138,6 +157,18 @@
return isUpdated; return isUpdated;
} }
/// <summary>
/// Adds the image to the cache in an asynchronous manner.
/// </summary>
/// <param name="stream">
/// The stream containing the image data.
/// </param>
/// <param name="contentType">
/// The content type of the image.
/// </param>
/// <returns>
/// The <see cref="Task"/> representing an asynchronous operation.
/// </returns>
public override async Task AddImageToCacheAsync(Stream stream, string contentType) public override async Task AddImageToCacheAsync(Stream stream, string contentType)
{ {
// ReSharper disable once AssignNullToNotNullAttribute // ReSharper disable once AssignNullToNotNullAttribute
@ -153,6 +184,12 @@
} }
} }
/// <summary>
/// Trims the cache of any expired items in an asynchronous manner.
/// </summary>
/// <returns>
/// The asynchronous <see cref="Task"/> representing an asynchronous operation.
/// </returns>
public override async Task TrimCacheAsync() public override async Task TrimCacheAsync()
{ {
string directory = Path.GetDirectoryName(this.CachedPath); string directory = Path.GetDirectoryName(this.CachedPath);
@ -198,6 +235,12 @@
} }
} }
/// <summary>
/// Rewrites the path to point to the cached image.
/// </summary>
/// <param name="context">
/// The <see cref="HttpContext"/> encapsulating all information about the request.
/// </param>
public override void RewritePath(HttpContext context) public override void RewritePath(HttpContext context)
{ {
// The cached file is valid so just rewrite the path. // The cached file is valid so just rewrite the path.

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

@ -1,4 +1,13 @@
 // --------------------------------------------------------------------------------------------------------------------
// <copyright file="IImageCache.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Defines properties and methods for allowing caching of images to different sources.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Web.Caching namespace ImageProcessor.Web.Caching
{ {
using System.Collections.Generic; using System.Collections.Generic;
@ -6,6 +15,9 @@ namespace ImageProcessor.Web.Caching
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
/// <summary>
/// Defines properties and methods for allowing caching of images to different sources.
/// </summary>
public interface IImageCache public interface IImageCache
{ {
/// <summary> /// <summary>
@ -13,20 +25,60 @@ namespace ImageProcessor.Web.Caching
/// </summary> /// </summary>
Dictionary<string, string> Settings { get; set; } Dictionary<string, string> Settings { get; set; }
/// <summary>
/// Gets the path to the cached image.
/// </summary>
string CachedPath { get; } string CachedPath { get; }
/// <summary>
/// Gets the maximum number of days to store the image.
/// </summary>
int MaxDays { get; } int MaxDays { get; }
/// <summary>
/// Gets a value indicating whether the image is new or updated in an asynchronous manner.
/// </summary>
/// <returns>
/// The asynchronous <see cref="Task"/> returning the value.
/// </returns>
Task<bool> IsNewOrUpdatedAsync(); Task<bool> IsNewOrUpdatedAsync();
/// <summary>
/// Adds the image to the cache in an asynchronous manner.
/// </summary>
/// <param name="stream">
/// The stream containing the image data.
/// </param>
/// <param name="contentType">
/// The content type of the image.
/// </param>
/// <returns>
/// The <see cref="Task"/> representing an asynchronous operation.
/// </returns>
Task AddImageToCacheAsync(Stream stream, string contentType); Task AddImageToCacheAsync(Stream stream, string contentType);
/// <summary>
/// Trims the cache of any expired items in an asynchronous manner.
/// </summary>
/// <returns>
/// The asynchronous <see cref="Task"/> representing an asynchronous operation.
/// </returns>
Task TrimCacheAsync(); Task TrimCacheAsync();
/// <summary>
/// Gets a string identifying the cached file name.
/// </summary>
/// <returns>
/// The asynchronous <see cref="Task"/> returning the value.
/// </returns>
Task<string> CreateCachedFileName(); Task<string> CreateCachedFileName();
/// <summary>
/// Rewrites the path to point to the cached image.
/// </summary>
/// <param name="context">
/// The <see cref="HttpContext"/> encapsulating all information about the request.
/// </param>
void RewritePath(HttpContext context); void RewritePath(HttpContext context);
//void SetHeaders(HttpContext context);
} }
} }

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

@ -1,10 +1,20 @@
namespace ImageProcessor.Web.Caching // --------------------------------------------------------------------------------------------------------------------
// <copyright file="ImageCacheBase.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// The image cache base provides methods for implementing the <see cref="IImageCache" /> interface.
// It is recommended that any implementations inherit from this class.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Web.Caching
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
@ -12,6 +22,10 @@
using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Extensions;
using ImageProcessor.Web.Helpers; using ImageProcessor.Web.Helpers;
/// <summary>
/// The image cache base provides methods for implementing the <see cref="IImageCache"/> interface.
/// It is recommended that any implementations inherit from this class.
/// </summary>
public abstract class ImageCacheBase : IImageCache public abstract class ImageCacheBase : IImageCache
{ {
/// <summary> /// <summary>
@ -54,16 +68,52 @@
/// </summary> /// </summary>
public Dictionary<string, string> Settings { get; set; } public Dictionary<string, string> Settings { get; set; }
public string CachedPath { get; protected set; } /// <summary>
/// Gets or sets the path to the cached image.
/// </summary>
public string CachedPath { get; set; }
/// <summary>
/// Gets the maximum number of days to store the image.
/// </summary>
public abstract int MaxDays { get; } public abstract int MaxDays { get; }
/// <summary>
/// Gets a value indicating whether the image is new or updated in an asynchronous manner.
/// </summary>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public abstract Task<bool> IsNewOrUpdatedAsync(); public abstract Task<bool> IsNewOrUpdatedAsync();
/// <summary>
/// Adds the image to the cache in an asynchronous manner.
/// </summary>
/// <param name="stream">
/// The stream containing the image data.
/// </param>
/// <param name="contentType">
/// The content type of the image.
/// </param>
/// <returns>
/// The <see cref="Task"/> representing an asynchronous operation.
/// </returns>
public abstract Task AddImageToCacheAsync(Stream stream, string contentType); public abstract Task AddImageToCacheAsync(Stream stream, string contentType);
/// <summary>
/// Trims the cache of any expired items in an asynchronous manner.
/// </summary>
/// <returns>
/// The asynchronous <see cref="Task"/> representing an asynchronous operation.
/// </returns>
public abstract Task TrimCacheAsync(); public abstract Task TrimCacheAsync();
/// <summary>
/// Gets a string identifying the cached file name.
/// </summary>
/// <returns>
/// The asynchronous <see cref="Task"/> returning the value.
/// </returns>
public virtual Task<string> CreateCachedFileName() public virtual Task<string> CreateCachedFileName()
{ {
string streamHash = string.Empty; string streamHash = string.Empty;
@ -106,6 +156,12 @@
return Task.FromResult(cachedFileName); return Task.FromResult(cachedFileName);
} }
/// <summary>
/// Rewrites the path to point to the cached image.
/// </summary>
/// <param name="context">
/// The <see cref="HttpContext"/> encapsulating all information about the request.
/// </param>
public abstract void RewritePath(HttpContext context); public abstract void RewritePath(HttpContext context);
/// <summary> /// <summary>

4
src/ImageProcessor.Web/Services/IImageService.cs

@ -4,7 +4,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary> // <summary>
// Defines properties and methods for allowing retrieval of image from different sources. // Defines properties and methods for allowing retrieval of images from different sources.
// </summary> // </summary>
// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------
@ -15,7 +15,7 @@ namespace ImageProcessor.Web.Services
using System.Threading.Tasks; using System.Threading.Tasks;
/// <summary> /// <summary>
/// Defines properties and methods for allowing retrieval of image from different sources. /// Defines properties and methods for allowing retrieval of images from different sources.
/// </summary> /// </summary>
public interface IImageService public interface IImageService
{ {

1
src/ImageProcessor.Web/Settings.StyleCop

@ -1,6 +1,7 @@
<StyleCopSettings Version="105"> <StyleCopSettings Version="105">
<GlobalSettings> <GlobalSettings>
<CollectionProperty Name="RecognizedWords"> <CollectionProperty Name="RecognizedWords">
<Value>cdn</Value>
<Value>dllimport</Value> <Value>dllimport</Value>
</CollectionProperty> </CollectionProperty>
</GlobalSettings> </GlobalSettings>

Loading…
Cancel
Save