Browse Source

Initial commit

TODO: Remote setting plus further integration.

Former-commit-id: 609b9c973cd86e6e0d40ebe4330d185151ae1b1a
pull/17/head
James South 12 years ago
parent
commit
df4305dbac
  1. 2
      src/ImageProcessor.Web/Configuration/ImageProcessingSection.cs
  2. 119
      src/ImageProcessor.Web/Configuration/ImageProcessorConfiguration.cs
  3. 307
      src/ImageProcessor.Web/Configuration/ImageSecuritySection.cs
  4. 3
      src/ImageProcessor.Web/ImageProcessor.Web.csproj
  5. 51
      src/ImageProcessor.Web/Services/IImageService.cs
  6. 86
      src/ImageProcessor.Web/Services/LocalFileImageService.cs
  7. 105
      src/ImageProcessor.Web/Services/RemoteImageService.cs

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

@ -155,7 +155,7 @@ namespace ImageProcessor.Web.Configuration
/// </summary>
/// <param name="index">The index at which to get the specified object.</param>
/// <returns>
/// The the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.PresetElement"/>
/// The <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.PresetElement"/>
/// at the specified index within the collection.
/// </returns>
public PresetElement this[int index]

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

@ -20,6 +20,7 @@ namespace ImageProcessor.Web.Configuration
using ImageProcessor.Common.Extensions;
using ImageProcessor.Processors;
using ImageProcessor.Web.Processors;
using ImageProcessor.Web.Services;
/// <summary>
/// Encapsulates methods to allow the retrieval of ImageProcessor settings.
@ -72,6 +73,7 @@ namespace ImageProcessor.Web.Configuration
private ImageProcessorConfiguration()
{
this.LoadGraphicsProcessors();
this.LoadImageServices();
}
#endregion
@ -92,6 +94,11 @@ namespace ImageProcessor.Web.Configuration
/// </summary>
public IList<IWebGraphicsProcessor> GraphicsProcessors { get; private set; }
/// <summary>
/// Gets the list of available ImageServices.
/// </summary>
public IList<IImageService> ImageServices { get; private set; }
/// <summary>
/// Gets a value indicating whether to preserve exif meta data.
/// </summary>
@ -136,7 +143,7 @@ namespace ImageProcessor.Web.Configuration
{
get
{
return GetImageSecuritySection().WhiteList.Cast<ImageSecuritySection.SafeUrl>().Select(x => x.Url).ToArray();
return GetImageSecuritySection().ImageServices.Cast<ImageSecuritySection.SafeUrl>().Select(x => x.Url).ToArray();
}
}
@ -147,7 +154,7 @@ namespace ImageProcessor.Web.Configuration
{
get
{
return GetImageSecuritySection().WhiteList.Cast<ImageSecuritySection.SafeUrl>().ToArray();
return GetImageSecuritySection().ImageServices.Cast<ImageSecuritySection.SafeUrl>().ToArray();
}
}
@ -258,6 +265,43 @@ namespace ImageProcessor.Web.Configuration
});
}
/// <summary>
/// Returns the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.SettingElementCollection"/> for the given plugin.
/// </summary>
/// <param name="name">
/// The name of the plugin to get the settings for.
/// </param>
/// <returns>
/// The <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.SettingElementCollection"/> for the given plugin.
/// </returns>
public Dictionary<string, string> GetServiceSettings(string name)
{
return PluginSettings.GetOrAdd(
name,
n =>
{
ImageSecuritySection.ServiceElement pluginElement = GetImageSecuritySection()
.ImageServices
.Cast<ImageSecuritySection.ServiceElement>()
.FirstOrDefault(x => x.Name == n);
Dictionary<string, string> settings;
if (pluginElement != null)
{
settings = pluginElement.Settings
.Cast<ImageProcessingSection.SettingElement>()
.ToDictionary(setting => setting.Key, setting => setting.Value);
}
else
{
settings = new Dictionary<string, string>();
}
return settings;
});
}
/// <summary>
/// Retrieves the processing configuration section from the current application configuration.
/// </summary>
@ -325,11 +369,51 @@ namespace ImageProcessor.Web.Configuration
}
}
/// <summary>
/// Gets the list of available ImageServices.
/// </summary>
private void LoadImageServices()
{
if (this.ImageServices == null)
{
if (GetImageSecuritySection().ImageServices.AutoLoadPlugins)
{
Type type = typeof(IImageService);
try
{
// Build a list of native IGraphicsProcessor instances.
List<Type> availableTypes = BuildManager.GetReferencedAssemblies()
.Cast<Assembly>()
.SelectMany(s => s.GetLoadableTypes())
.Where(t => type.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract)
.ToList();
// Create them and add.
this.ImageServices = availableTypes.Select(x => (Activator.CreateInstance(x) as IImageService)).ToList();
// Add the available settings.
foreach (IImageService imageService in this.ImageServices)
{
imageService.Settings = this.GetServiceSettings(imageService.GetType().Name);
}
}
catch (ReflectionTypeLoadException)
{
this.LoadImageServicesFromConfiguration();
}
}
else
{
this.LoadImageServicesFromConfiguration();
}
}
}
/// <summary>
/// Loads graphics processors from configuration.
/// </summary>
/// <exception cref="TypeLoadException">
/// Thrown when an <see cref="IGraphicsProcessor"/> cannot be loaded.
/// Thrown when an <see cref="IWebGraphicsProcessor"/> cannot be loaded.
/// </exception>
private void LoadGraphicsProcessorsFromConfiguration()
{
@ -353,6 +437,35 @@ namespace ImageProcessor.Web.Configuration
webProcessor.Processor.Settings = this.GetPluginSettings(webProcessor.GetType().Name);
}
}
/// <summary>
/// Loads image services from configuration.
/// </summary>
/// <exception cref="TypeLoadException">
/// Thrown when an <see cref="IGraphicsProcessor"/> cannot be loaded.
/// </exception>
private void LoadImageServicesFromConfiguration()
{
ImageSecuritySection.ServiceElementCollection services = imageSecuritySection.ImageServices;
this.ImageServices = new List<IImageService>();
foreach (ImageSecuritySection.ServiceElement config in services)
{
Type type = Type.GetType(config.Type);
if (type == null)
{
throw new TypeLoadException("Couldn't load IImageService: " + config.Type);
}
this.GraphicsProcessors.Add(Activator.CreateInstance(type) as IWebGraphicsProcessor);
}
// Add the available settings.
foreach (IImageService service in this.ImageServices)
{
service.Settings = this.GetServiceSettings(service.GetType().Name);
}
}
#endregion
}
}

307
src/ImageProcessor.Web/Configuration/ImageSecuritySection.cs

@ -10,16 +10,14 @@
namespace ImageProcessor.Web.Configuration
{
#region Using
using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml;
using ImageProcessor.Web.Helpers;
#endregion
/// <summary>
/// Represents an image security section within a configuration file.
/// </summary>
@ -91,13 +89,13 @@ namespace ImageProcessor.Web.Configuration
/// Gets the <see cref="T:ImageProcessor.Web.Config.ImageSecuritySection.WhiteListElementCollection"/>
/// </summary>
/// <value>The <see cref="T:ImageProcessor.Web.Config.ImageSecuritySection.WhiteListElementCollection"/></value>
[ConfigurationProperty("whiteList", IsRequired = true)]
public WhiteListElementCollection WhiteList
[ConfigurationProperty("services", IsRequired = true)]
public ServiceElementCollection ImageServices
{
get
{
object o = this["whiteList"];
return o as WhiteListElementCollection;
object o = this["services"];
return o as ServiceElementCollection;
}
}
#endregion
@ -125,6 +123,301 @@ namespace ImageProcessor.Web.Configuration
}
#endregion
/// <summary>
/// Represents a ServiceElement configuration element within the configuration.
/// </summary>
public class ServiceElement : ConfigurationElement
{
/// <summary>
/// Gets or sets the name of the plugin file.
/// </summary>
/// <value>The name of the plugin.</value>
[ConfigurationProperty("name", DefaultValue = "", IsRequired = true)]
public string Name
{
get { return (string)this["name"]; }
set { this["name"] = value; }
}
/// <summary>
/// Gets or sets the type of the service file.
/// </summary>
/// <value>The full Type definition of the plugin</value>
[ConfigurationProperty("type", DefaultValue = "", IsRequired = true)]
public string Type
{
get { return (string)this["type"]; }
set { this["type"] = value; }
}
/// <summary>
/// Gets the <see cref="T:ImageProcessor.Web.Config.ImageSecuritySection.SettingElementCollection"/>.
/// </summary>
/// <value>
/// The <see cref="T:ImageProcessor.Web.Config.ImageSecuritySection.SettingElementCollection"/>.
/// </value>
[ConfigurationProperty("settings", IsRequired = false)]
public SettingElementCollection Settings
{
get
{
return this["settings"] as SettingElementCollection;
}
}
/// <summary>
/// Gets the <see cref="T:ImageProcessor.Web.Config.ImageSecuritySection.WhiteListElementCollection"/>.
/// </summary>
/// <value>
/// The <see cref="T:ImageProcessor.Web.Config.ImageSecuritySection.WhiteListElementCollection"/>.
/// </value>
[ConfigurationProperty("whitelist", IsRequired = false)]
public WhiteListElementCollection WhiteList
{
get
{
return this["whitelist"] as WhiteListElementCollection;
}
}
}
/// <summary>
/// Represents a collection of <see cref="ServiceElement"/> elements within the configuration.
/// </summary>
public class ServiceElementCollection : ConfigurationElementCollection
{
/// <summary>
/// Gets or sets a value indicating whether to auto load all plugins.
/// <remarks>Defaults to <value>True</value>.</remarks>
/// </summary>
/// <value>If True plugins are auto discovered and loaded from all assemblies otherwise they must be defined in the configuration file</value>
[ConfigurationProperty("autoLoadPlugins", DefaultValue = true, IsRequired = false)]
public bool AutoLoadPlugins
{
get { return (bool)this["autoLoadPlugins"]; }
set { this["autoLoadPlugins"] = value; }
}
/// <summary>
/// Gets the type of the <see cref="T:System.Configuration.ConfigurationElementCollection"/>.
/// </summary>
/// <value>
/// The <see cref="T:System.Configuration.ConfigurationElementCollectionType"/> of this collection.
/// </value>
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMap; }
}
/// <summary>
/// Gets the name used to identify this collection of elements in the configuration file when overridden in a derived class.
/// </summary>
/// <value>
/// The name of the collection; otherwise, an empty string. The default is an empty string.
/// </value>
protected override string ElementName
{
get { return "service"; }
}
/// <summary>
/// Gets or sets the <see cref="T:ImageProcessor.Web.Config.ImageSecuritySection.ServiceElement"/>
/// at the specified index within the collection.
/// </summary>
/// <param name="index">The index at which to get the specified object.</param>
/// <returns>
/// The <see cref="T:ImageProcessor.Web.Config.ImageSecuritySection.ServiceElement"/>
/// at the specified index within the collection.
/// </returns>
public ServiceElement this[int index]
{
get
{
return (ServiceElement)BaseGet(index);
}
set
{
if (this.BaseGet(index) != null)
{
this.BaseRemoveAt(index);
}
this.BaseAdd(index, value);
}
}
/// <summary>
/// When overridden in a derived class, creates a new <see cref="T:System.Configuration.ConfigurationElement"/>.
/// </summary>
/// <returns>
/// A new <see cref="T:System.Configuration.ConfigurationElement"/>.
/// </returns>
protected override ConfigurationElement CreateNewElement()
{
return new ServiceElement();
}
/// <summary>
/// Gets the element key for a specified configuration element when overridden in a derived class.
/// </summary>
/// <returns>
/// An <see cref="T:System.Object"/> that acts as the key for the specified <see cref="T:System.Configuration.ConfigurationElement"/>.
/// </returns>
/// <param name="element">The <see cref="T:System.Configuration.ConfigurationElement"/> to return the key for. </param>
protected override object GetElementKey(ConfigurationElement element)
{
return ((ServiceElement)element).Name;
}
}
/// <summary>
/// Represents a SettingElement configuration element within the configuration.
/// </summary>
public class SettingElement : ConfigurationElement
{
/// <summary>
/// Gets or sets the key of the plugin setting.
/// </summary>
/// <value>The key of the plugin setting.</value>
[ConfigurationProperty("key", IsRequired = true, IsKey = true)]
public string Key
{
get
{
return this["key"] as string;
}
set
{
this["key"] = value;
}
}
/// <summary>
/// Gets or sets the value of the plugin setting.
/// </summary>
/// <value>The value of the plugin setting.</value>
[ConfigurationProperty("value", IsRequired = true)]
public string Value
{
get
{
return (string)this["value"];
}
set
{
this["value"] = value;
}
}
}
/// <summary>
/// Represents a SettingElementCollection collection configuration element within the configuration.
/// </summary>
public class SettingElementCollection : ConfigurationElementCollection
{
/// <summary>
/// Gets the type of the <see cref="T:System.Configuration.ConfigurationElementCollection"/>.
/// </summary>
/// <value>
/// The <see cref="T:System.Configuration.ConfigurationElementCollectionType"/> of this collection.
/// </value>
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMap; }
}
/// <summary>
/// Gets the name used to identify this collection of elements in the configuration file when overridden in a derived class.
/// </summary>
/// <value>
/// The name of the collection; otherwise, an empty string. The default is an empty string.
/// </value>
protected override string ElementName
{
get { return "setting"; }
}
/// <summary>
/// Gets or sets the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.SettingElement"/>
/// at the specified index within the collection.
/// </summary>
/// <param name="index">The index at which to get the specified object.</param>
/// <returns>
/// The the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.SettingElement"/>
/// at the specified index within the collection.
/// </returns>
public ImageProcessingSection.SettingElement this[int index]
{
get
{
return (ImageProcessingSection.SettingElement)BaseGet(index);
}
set
{
if (this.BaseGet(index) != null)
{
this.BaseRemoveAt(index);
}
this.BaseAdd(index, value);
}
}
/// <summary>
/// Returns the setting element with the specified key.
/// </summary>
/// <param name="key">the key representing the element</param>
/// <returns>the setting element</returns>
public new ImageProcessingSection.SettingElement this[string key]
{
get { return (ImageProcessingSection.SettingElement)BaseGet(key); }
}
/// <summary>
/// Returns a value indicating whether the settings collection contains the
/// given object.
/// </summary>
/// <param name="key">The key to identify the setting.</param>
/// <returns>True if the collection contains the key; otherwise false.</returns>
public bool ContainsKey(string key)
{
object[] keys = BaseGetAllKeys();
return keys.Any(obj => (string)obj == key);
}
/// <summary>
/// Gets the element key for a specified PluginElement configuration element.
/// </summary>
/// <param name="element">
/// The <see cref="T:System.Configuration.ConfigurationElement">ConfigurationElement</see>
/// to return the key for.
/// </param>
/// <returns>The element key for a specified PluginElement configuration element.</returns>
protected override object GetElementKey(ConfigurationElement element)
{
return ((ImageProcessingSection.SettingElement)element).Key;
}
/// <summary>
/// Creates a new SettingElement configuration element.
/// </summary>
/// <returns>
/// A new SettingElement configuration element.
/// </returns>
protected override ConfigurationElement CreateNewElement()
{
return new ImageProcessingSection.SettingElement();
}
}
/// <summary>
/// Represents a whitelist collection configuration element within the configuration.
/// </summary>

3
src/ImageProcessor.Web/ImageProcessor.Web.csproj

@ -46,6 +46,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Caching\CachedImage.cs" />
<Compile Include="Services\IImageService.cs" />
<Compile Include="Caching\MemCache.cs" />
<Compile Include="Caching\DiskCache.cs" />
<Compile Include="Caching\CacheIndexer.cs" />
@ -86,6 +87,8 @@
<Compile Include="Processors\Vignette.cs" />
<Compile Include="Processors\Watermark.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\LocalFileImageService.cs" />
<Compile Include="Services\RemoteImageService.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageProcessor\ImageProcessor.csproj">

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

@ -0,0 +1,51 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="IImageService.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Defines properties and methods for allowing retrieval of image from different means.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Web.Services
{
using System.Collections.Generic;
using System.Threading.Tasks;
/// <summary>
/// Defines properties and methods for allowing retrieval of image from different means.
/// </summary>
public interface IImageService
{
/// <summary>
/// Gets the key for the given implementation.
/// <remarks>
/// This value is used as a prefix for any image requests that should use this service.
/// </remarks>
/// </summary>
string Key { get; }
/// <summary>
/// Gets a value indicating whether the image service requests files from
/// the locally based file system.
/// </summary>
bool IsFileLocalService { get; }
/// <summary>
/// Gets or sets any additional settings required by the service.
/// </summary>
Dictionary<string, string> Settings { get; set; }
/// <summary>
/// Gets the image using the given identifier.
/// </summary>
/// <param name="id">
/// The value identifying the image to fetch.
/// </param>
/// <returns>
/// The <see cref="System.Byte"/> array containing the image data.
/// </returns>
Task<byte[]> GetImage(object id);
}
}

86
src/ImageProcessor.Web/Services/LocalFileImageService.cs

@ -0,0 +1,86 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="LocalFileImageService.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// The local file image service for retrieving images from the file system.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Web.Services
{
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Web;
/// <summary>
/// The local file image service for retrieving images from the file system.
/// </summary>
public class LocalFileImageService : IImageService
{
/// <summary>
/// Gets the key for the given implementation.
/// <remarks>
/// This value is used as a prefix for any image requests that should use this service.
/// </remarks>
/// </summary>
public string Key
{
get
{
return string.Empty;
}
}
/// <summary>
/// Gets a value indicating whether the image service requests files from
/// the locally based file system.
/// </summary>
public bool IsFileLocalService
{
get
{
return true;
}
}
/// <summary>
/// Gets or sets any additional settings required by the service.
/// </summary>
public Dictionary<string, string> Settings { get; set; }
/// <summary>
/// Gets the image using the given identifier.
/// </summary>
/// <param name="id">
/// The value identifying the image to fetch.
/// </param>
/// <returns>
/// The <see cref="System.Byte"/> array containing the image data.
/// </returns>
public async Task<byte[]> GetImage(object id)
{
string path = id.ToString();
byte[] buffer;
// Check to see if the file exists.
// ReSharper disable once AssignNullToNotNullAttribute
FileInfo fileInfo = new FileInfo(path);
if (!fileInfo.Exists)
{
throw new HttpException(404, "No image exists at " + path);
}
using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
{
buffer = new byte[file.Length];
await file.ReadAsync(buffer, 0, (int)file.Length);
}
return buffer;
}
}
}

105
src/ImageProcessor.Web/Services/RemoteImageService.cs

@ -0,0 +1,105 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="RemoteImageService.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// The remote image service.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Web.Services
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using ImageProcessor.Web.Helpers;
/// <summary>
/// The remote image service.
/// </summary>
public class RemoteImageService : IImageService
{
/// <summary>
/// Initializes a new instance of the <see cref="RemoteImageService"/> class.
/// </summary>
public RemoteImageService()
{
this.Settings = new Dictionary<string, string>();
}
/// <summary>
/// Gets the key for the given implementation.
/// <remarks>
/// This value is used as a prefix for any image requests that should use this service.
/// </remarks>
/// </summary>
public string Key
{
get
{
return "remote.axd";
}
}
/// <summary>
/// Gets a value indicating whether the image service requests files from
/// the locally based file system.
/// </summary>
public bool IsFileLocalService
{
get
{
return false;
}
}
/// <summary>
/// Gets or sets any additional settings required by the service.
/// </summary>
public Dictionary<string, string> Settings { get; set; }
/// <summary>
/// Gets the image using the given identifier.
/// </summary>
/// <param name="id">
/// The value identifying the image to fetch.
/// </param>
/// <returns>
/// The <see cref="System.Byte"/> array containing the image data.
/// </returns>
public async Task<byte[]> GetImage(object id)
{
Uri uri = new Uri(id.ToString());
RemoteFile remoteFile = new RemoteFile(uri, false);
byte[] buffer = { };
// Prevent response blocking.
WebResponse webResponse = await remoteFile.GetWebResponseAsync().ConfigureAwait(false);
using (MemoryStream memoryStream = new MemoryStream())
{
using (WebResponse response = webResponse)
{
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
responseStream.CopyTo(memoryStream);
// Reset the position of the stream to ensure we're reading the correct part.
memoryStream.Position = 0;
buffer = memoryStream.ToArray();
}
}
}
}
return buffer;
}
}
}
Loading…
Cancel
Save