Browse Source

Async optimisation complete.

Former-commit-id: a717ad1fae85e712966038efbdb99a383f1361d8
af/merge-core
JimBobSquarePants 13 years ago
parent
commit
f717c8e22f
  1. 13
      APACHE-2.0-LICENSE.txt
  2. 3
      src/ImageProcessor.Tests/ImageProcessor.Tests.csproj
  3. 114
      src/ImageProcessor.Tests/RegularExpressionUnitTests.cs
  4. 15
      src/ImageProcessor.Tests/app.config
  5. 457
      src/ImageProcessor.Web/Caching/Cache.cs
  6. 10
      src/ImageProcessor.Web/Caching/CachedImage.cs
  7. 346
      src/ImageProcessor.Web/Caching/Copy of DiskCache.cs
  8. 367
      src/ImageProcessor.Web/Caching/DiskCache.cs
  9. 44
      src/ImageProcessor.Web/Caching/PersistantDictionary.cs
  10. 142
      src/ImageProcessor.Web/Caching/SQLContext.cs
  11. 4
      src/ImageProcessor.Web/Config/ImageCacheSection.cs
  12. 4
      src/ImageProcessor.Web/Config/ImageProcessingSection.cs
  13. 6
      src/ImageProcessor.Web/Config/ImageProcessorConfig.cs
  14. 16
      src/ImageProcessor.Web/Config/ImageSecuritySection.cs
  15. 64
      src/ImageProcessor.Web/Helpers/AsyncIoExtensions.cs
  16. 347
      src/ImageProcessor.Web/Helpers/Copy of RemoteFile.cs
  17. 2
      src/ImageProcessor.Web/Helpers/LockedDictionary.cs
  18. 52
      src/ImageProcessor.Web/Helpers/ObjectFactory.cs
  19. 20
      src/ImageProcessor.Web/Helpers/ProcessorFactory.cs
  20. 81
      src/ImageProcessor.Web/Helpers/RemoteFile.cs
  21. 174
      src/ImageProcessor.Web/Helpers/TaskEx.cs
  22. 52
      src/ImageProcessor.Web/Helpers/TaskHelpers.cs
  23. 342
      src/ImageProcessor.Web/HttpModules/Copy of ImageProcessingModule.cs
  24. 220
      src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs
  25. 7
      src/ImageProcessor.Web/ImageFactoryExtensions.cs
  26. 31
      src/ImageProcessor.Web/ImageProcessor.Web.csproj
  27. 4
      src/ImageProcessor.Web/Properties/AssemblyInfo.cs
  28. 15
      src/ImageProcessor.Web/app.config
  29. 3
      src/ImageProcessor.Web/packages.config
  30. 2
      src/ImageProcessor/Helpers/Extensions/EnumExtensions.cs
  31. 2
      src/ImageProcessor/Helpers/Extensions/StringExtensions.cs
  32. 2
      src/ImageProcessor/ImageFactory.cs
  33. 2
      src/ImageProcessor/Imaging/Filters/BlackWhiteMatrixFilter.cs
  34. 2
      src/ImageProcessor/Imaging/Filters/ColorMatrixes.cs
  35. 2
      src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs
  36. 2
      src/ImageProcessor/Imaging/Filters/GothamMatrixFilter.cs
  37. 2
      src/ImageProcessor/Imaging/Filters/GreyScaleMatrixFilter.cs
  38. 2
      src/ImageProcessor/Imaging/Filters/HiSatchMatrixFilter.cs
  39. 2
      src/ImageProcessor/Imaging/Filters/IMatrixFilter.cs
  40. 2
      src/ImageProcessor/Imaging/Filters/InvertMatrixFilter.cs
  41. 2
      src/ImageProcessor/Imaging/Filters/LoSatchMatrixFilter.cs
  42. 2
      src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs
  43. 2
      src/ImageProcessor/Imaging/Filters/PolaroidMatrixFilter.cs
  44. 2
      src/ImageProcessor/Imaging/Filters/SepiaMatrixFilter.cs
  45. 2
      src/ImageProcessor/Imaging/ImageUtils.cs
  46. 2
      src/ImageProcessor/Imaging/OctreeQuantizer.cs
  47. 2
      src/ImageProcessor/Imaging/Quantizer.cs
  48. 2
      src/ImageProcessor/Imaging/ResponseType.cs
  49. 2
      src/ImageProcessor/Imaging/RotateLayer.cs
  50. 2
      src/ImageProcessor/Imaging/TextLayer.cs
  51. 2
      src/ImageProcessor/Processors/Alpha.cs
  52. 4
      src/ImageProcessor/Processors/Crop.cs
  53. 2
      src/ImageProcessor/Processors/Filter.cs
  54. 2
      src/ImageProcessor/Processors/Flip.cs
  55. 2
      src/ImageProcessor/Processors/Format.cs
  56. 2
      src/ImageProcessor/Processors/IGraphicsProcessor.cs
  57. 2
      src/ImageProcessor/Processors/Quality.cs
  58. 2
      src/ImageProcessor/Processors/Resize.cs
  59. 2
      src/ImageProcessor/Processors/Rotate.cs
  60. 2
      src/ImageProcessor/Processors/Vignette.cs
  61. 2
      src/ImageProcessor/Processors/Watermark.cs
  62. 4
      src/ImageProcessor/Properties/AssemblyInfo.cs
  63. 25
      src/Test/Test/Controllers/HomeController.cs
  64. 2
      src/Test/Test/Images/Thumbs.db.REMOVED.git-id
  65. 0
      src/Test/Test/Images/udendørs.jpg.REMOVED.git-id
  66. 4
      src/Test/Test/Test.csproj
  67. 1
      src/Test/Test/Views/Home/Collisions.cshtml
  68. 2
      src/Test/Test/Views/Home/Index.cshtml
  69. 64
      src/Test/Test/Web.config
  70. 1
      src/packages/Microsoft.Bcl.1.0.16-rc/License.rtf.REMOVED.git-id
  71. 1
      src/packages/Microsoft.Bcl.1.0.16-rc/Microsoft.Bcl.1.0.16-rc.nupkg.REMOVED.git-id
  72. 44
      src/packages/Microsoft.Bcl.1.0.16-rc/Microsoft.Bcl.1.0.16-rc.nuspec
  73. 24
      src/packages/Microsoft.Bcl.1.0.16-rc/ReleaseNotes.txt
  74. 15
      src/packages/Microsoft.Bcl.1.0.16-rc/content/net40/app.config.transform
  75. 15
      src/packages/Microsoft.Bcl.1.0.16-rc/content/net40/web.config.transform
  76. 0
      src/packages/Microsoft.Bcl.1.0.16-rc/content/net45/_._
  77. 15
      src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+sl4+win8+wp71/app.config.transform
  78. 15
      src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+sl4+win8+wp8/app.config.transform
  79. 15
      src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+sl4+win8/app.config.transform
  80. 15
      src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+sl5+win8+wp8/app.config.transform
  81. 15
      src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+win8+wp8/app.config.transform
  82. 15
      src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+win8/app.config.transform
  83. 0
      src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net45+win8+wp8/_._
  84. 15
      src/packages/Microsoft.Bcl.1.0.16-rc/content/sl4-windowsphone71/app.config.transform
  85. 0
      src/packages/Microsoft.Bcl.1.0.16-rc/content/sl4/_._
  86. 0
      src/packages/Microsoft.Bcl.1.0.16-rc/content/sl5/_._
  87. 0
      src/packages/Microsoft.Bcl.1.0.16-rc/content/win8/_._
  88. 0
      src/packages/Microsoft.Bcl.1.0.16-rc/content/wp8/_._
  89. BIN
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/net40/System.Runtime.dll
  90. 56
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/net40/System.Runtime.xml
  91. BIN
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/net40/System.Threading.Tasks.dll
  92. 475
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/net40/System.Threading.Tasks.xml
  93. 0
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/net45/_._
  94. BIN
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp71/System.Runtime.dll
  95. 860
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp71/System.Runtime.xml
  96. 1
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp71/System.Threading.Tasks.dll.REMOVED.git-id
  97. 1
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp71/System.Threading.Tasks.xml.REMOVED.git-id
  98. BIN
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp8/System.Runtime.dll
  99. 56
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp8/System.Runtime.xml
  100. 1
      src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp8/System.Threading.Tasks.dll.REMOVED.git-id

13
APACHE-2.0-LICENSE.txt

@ -0,0 +1,13 @@
Copyright 2012 James South
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

3
src/ImageProcessor.Tests/ImageProcessor.Tests.csproj

@ -83,6 +83,9 @@
<Name>ImageProcessor</Name> <Name>ImageProcessor</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<Choose> <Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'"> <When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup> <ItemGroup>

114
src/ImageProcessor.Tests/RegularExpressionUnitTests.cs

@ -1,67 +1,137 @@
namespace ImageProcessor.Tests // -----------------------------------------------------------------------
// <copyright file="RegularExpressionUnitTests.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// -----------------------------------------------------------------------
namespace ImageProcessor.Tests
{ {
#region Using #region Using
using System;
using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.IO;
using System.Text.RegularExpressions;
using ImageProcessor.Imaging; using ImageProcessor.Imaging;
using ImageProcessor.Processors; using ImageProcessor.Processors;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
#endregion #endregion
/// <summary>
/// The regular expression unit tests.
/// This is a work in progress. YAWN!
/// </summary>
[TestClass] [TestClass]
public class RegularExpressionUnitTests public class RegularExpressionUnitTests
{ {
#region Regular Expression Tests #region Regular Expression Tests
/// <summary>
/// The alpha regex unit test.
/// </summary>
[TestMethod] [TestMethod]
public void TestAlphaRegex() public void TestAlphaRegex()
{ {
const string querystring = "alpha=56"; const string Querystring = "alpha=56";
const int expected = 56; const int Expected = 56;
Alpha alpha = new Alpha(); Alpha alpha = new Alpha();
alpha.MatchRegexIndex(querystring); alpha.MatchRegexIndex(Querystring);
int actual = alpha.DynamicParameter; int actual = alpha.DynamicParameter;
Assert.AreEqual<int>(expected, actual); Assert.AreEqual(Expected, actual);
} }
/// <summary>
/// The rotate regex unit test.
/// </summary>
[TestMethod]
public void TestCropRegex()
{
const string Querystring = "crop=0-0-150-300";
Rectangle expected = new Rectangle(0, 0, 150, 300);
Crop crop = new Crop();
crop.MatchRegexIndex(Querystring);
Rectangle actual = crop.DynamicParameter;
Assert.AreEqual(expected, actual);
}
/// <summary>
/// The filter regex unit test.
/// </summary>
[TestMethod]
public void TestFilterRegex()
{
// Should really write more for the other filters.
const string Querystring = "filter=lomograph";
const string Expected = "lomograph";
Filter filter = new Filter();
filter.MatchRegexIndex(Querystring);
string actual = filter.DynamicParameter;
Assert.AreEqual(Expected, actual);
}
/// <summary>
/// The format regex unit test.
/// </summary>
[TestMethod] [TestMethod]
public void TestFormatRegex() public void TestFormatRegex()
{ {
string querystring = "format=gif"; const string Querystring = "format=gif";
string expected = "gif"; const string Expected = "gif";
Format format = new Format(); Format format = new Format();
format.MatchRegexIndex(querystring); format.MatchRegexIndex(Querystring);
string actual = format.DynamicParameter; string actual = format.DynamicParameter;
Assert.AreEqual(expected, actual); Assert.AreEqual(Expected, actual);
} }
/// <summary>
/// The quality regex unit test.
/// </summary>
[TestMethod] [TestMethod]
public void TestQualityRegex() public void TestQualityRegex()
{ {
string querystring = "quality=56"; const string Querystring = "quality=56";
int expected = 56; const int Expected = 56;
Quality quality = new Quality(); Quality quality = new Quality();
quality.MatchRegexIndex(querystring); quality.MatchRegexIndex(Querystring);
int actual = quality.DynamicParameter; int actual = quality.DynamicParameter;
Assert.AreEqual<int>(expected, actual); Assert.AreEqual(Expected, actual);
}
/// <summary>
/// The resize regex unit test.
/// </summary>
[TestMethod]
public void TestResizeRegex()
{
const string Querystring = "width=300";
Size expected = new Size(300, 0);
Resize resize = new Resize();
resize.MatchRegexIndex(Querystring);
Size actual = resize.DynamicParameter;
Assert.AreEqual(expected, actual);
} }
/// <summary>
/// The rotate regex unit test.
/// </summary>
[TestMethod] [TestMethod]
public void TestRotateRegex() public void TestRotateRegex()
{ {
// Why does this fail? const string Querystring = "rotate=270";
string querystring = "rotate=270";
RotateLayer expected = new RotateLayer RotateLayer expected = new RotateLayer
{ {
Angle = 270, Angle = 270,
@ -69,11 +139,13 @@
}; };
Rotate rotate = new Rotate(); Rotate rotate = new Rotate();
rotate.MatchRegexIndex(querystring); rotate.MatchRegexIndex(Querystring);
RotateLayer actual = rotate.DynamicParameter; RotateLayer actual = rotate.DynamicParameter;
Assert.AreEqual<RotateLayer>(expected, actual); // Can't use are equal on rotatelayer for some reason so test the two properties.
Assert.AreEqual(expected.Angle, actual.Angle);
Assert.AreEqual(expected.BackgroundColor, actual.BackgroundColor);
} }
#endregion #endregion
} }

15
src/ImageProcessor.Tests/app.config

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

457
src/ImageProcessor.Web/Caching/Cache.cs

@ -1,457 +0,0 @@
// -----------------------------------------------------------------------
// <copyright file="Cache.cs" company="James South">
// Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses.
// </copyright>
// -----------------------------------------------------------------------
namespace ImageProcessor.Web.Caching
{
#region Using
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Web.Hosting;
using ImageProcessor.Helpers.Extensions;
using ImageProcessor.Web.Config;
#endregion
/// <summary>
/// The cache.
/// </summary>
internal sealed class Cache
{
#region Fields
/// <summary>
/// The maximum number of days to cache files on the system for.
/// </summary>
internal static readonly int MaxFileCachedDuration = ImageProcessorConfig.Instance.MaxCacheDays;
/// <summary>
/// The valid sub directory chars. This used in combination with the file limit per folder
/// allows the storage of 360,000 image files in the cache.
/// </summary>
private const string ValidSubDirectoryChars = "abcdefghijklmnopqrstuvwxyz0123456789";
/// <summary>
/// The maximum number of files allowed in the directory.
/// </summary>
/// <remarks>
/// NTFS directories can handle up to 10,000 files in the directory before slowing down.
/// This will help us to ensure that don't go over that limit.
/// <see cref="http://stackoverflow.com/questions/197162/ntfs-performance-and-large-volumes-of-files-and-directories"/>
/// <see cref="http://stackoverflow.com/questions/115882/how-do-you-deal-with-lots-of-small-files"/>
/// <see cref="http://stackoverflow.com/questions/1638219/millions-of-small-graphics-files-and-how-to-overcome-slow-file-system-access-on"/>
/// </remarks>
private const int MaxFilesCount = 10000;
/// <summary>
/// The regular expression to search strings for file extensions.
/// </summary>
private static readonly Regex FormatRegex = new Regex(
@"(jpeg|png|bmp|gif)", RegexOptions.RightToLeft | RegexOptions.Compiled);
/// <summary>
/// The regular expression to search strings for valid subfolder names.
/// We're specifically not using a shorter regex as we need to be able to iterate through
/// each match group.
/// </summary>
private static readonly Regex SubFolderRegex =
new Regex(
@"(\/(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9)\/)",
RegexOptions.Compiled);
/// <summary>
/// The absolute path to virtual cache path on the server.
/// </summary>
private static readonly string AbsoluteCachePath =
HostingEnvironment.MapPath(ImageProcessorConfig.Instance.VirtualCachePath);
/// <summary>
/// The concurrent dictionary.
/// </summary>
private static ConcurrentDictionary<string, CachedImage> concurrentDictionary =
new ConcurrentDictionary<string, CachedImage>();
/// <summary>
/// The request path for the image.
/// </summary>
private string requestPath;
/// <summary>
/// The image name
/// </summary>
private string imageName;
/// <summary>
/// Whether the request is for a remote image.
/// </summary>
private bool isRemote;
#endregion
#region Constructors
public Cache(string requestPath, string fullPath, string imageName, bool isRemote)
{
this.requestPath = requestPath;
this.imageName = imageName;
this.isRemote = isRemote;
this.CachedPath = this.GetCachePath(fullPath, imageName);
}
#endregion
#region Properties
/// <summary>
/// Gets the cached path.
/// </summary>
internal string CachedPath { get; private set; }
#endregion
#region Methods
#region Internal
/// <summary>
/// Converts an absolute file path
/// </summary>
/// <param name="absolutePath">The absolute path to convert.</param>
/// <param name="request">The <see cref="T:System.Web.HttpRequest"/>from the current context.</param>
/// <returns>The virtual path to the file.</returns>
internal string GetVirtualPath(string absolutePath, HttpRequest request)
{
string applicationPath = request.PhysicalApplicationPath;
string virtualDir = request.ApplicationPath;
virtualDir = virtualDir == "/" ? virtualDir : (virtualDir + "/");
if (applicationPath != null)
{
return absolutePath.Replace(applicationPath, virtualDir).Replace(@"\", "/");
}
throw new InvalidOperationException(
"We can only map an absolute back to a relative path if the application path is available.");
}
/// <summary>
/// Creates the cache directories for storing images.
/// </summary>
/// <returns>
/// The true if the cache directories are created successfully; otherwise, false.
/// </returns>
internal static /*async*/ Task<bool> CreateDirectoriesAsync()
{
return CreateDirectoriesAsyncTasks().ToTask<bool>();
}
/// <summary>
/// Adds an image to the cache.
/// </summary>
/// <param name="cachedPath">
/// The cached path.
/// </param>
/// <param name="lastWriteTimeUtc">
/// The last write time.
/// </param>
/// <returns>
/// The task.
/// </returns>
internal Task /*async*/ AddImageToCacheAsync(DateTime lastWriteTimeUtc)
{
return this.AddImageToCacheAsyncTask(lastWriteTimeUtc).ToTask();
}
/// <summary>
/// Returns a value indicating whether the original file is new or has been updated.
/// </summary>
/// <returns>
/// True if the the original file is new or has been updated; otherwise, false.
/// </returns>
internal /*async*/ Task<bool> isNewOrUpdatedFileAsync()
{
return this.isNewOrUpdatedFileAsyncTask().ToTask<bool>();
}
/// <summary>
/// Sets the LastWriteTime of the cached file to match the original file.
/// </summary>
/// The <see cref="System.DateTime"/> set to the last write time of the file.
/// </returns>
internal /*async*/ Task<DateTime> SetCachedLastWriteTimeAsync()
{
return this.SetCachedLastWriteTimeAsyncTask().ToTask<DateTime>();
}
/// <summary>
/// Purges any files from the file-system cache in the given folders.
/// </summary>
internal /*async*/ Task TrimCachedFoldersAsync()
{
return this.TrimCachedFoldersAsyncTask().ToTask();
}
#endregion
#region Private
/// <summary>
/// The create directories async tasks.
/// </summary>
/// <returns>
/// The <see cref="IEnumerable{Task}"/>.
/// </returns>
private static IEnumerable<Task> CreateDirectoriesAsyncTasks()
{
bool success = true;
try
{
Parallel.ForEach(
ValidSubDirectoryChars.ToCharArray(),
(extension, loop) =>
{
string path = Path.Combine(AbsoluteCachePath, extension.ToString(CultureInfo.InvariantCulture));
DirectoryInfo directoryInfo = new DirectoryInfo(path);
if (!directoryInfo.Exists)
{
directoryInfo.Create();
}
});
}
catch
{
success = false;
}
yield return TaskEx.FromResult(success);
}
/// <summary>
/// Adds an image to the cache.
/// </summary>
/// <param name="lastWriteTimeUtc">
/// The last write time.
/// </param>
/// <returns>
/// The <see cref="IEnumerable{Task}"/>.
/// </returns>
private IEnumerable<Task> AddImageToCacheAsyncTask(DateTime lastWriteTimeUtc)
{
string key = Path.GetFileNameWithoutExtension(this.CachedPath);
DateTime expires = DateTime.UtcNow.AddDays(MaxFileCachedDuration).ToUniversalTime();
CachedImage cachedImage = new CachedImage(this.CachedPath, MaxFileCachedDuration, lastWriteTimeUtc, expires);
PersistantDictionary.Instance.Add(key, cachedImage);
yield break;
}
/// <summary>
/// Returns a value indicating whether the original file is new or has been updated.
/// </summary>
/// <returns>
/// The <see cref="IEnumerable{Task}"/>.
/// </returns>
private IEnumerable<Task> isNewOrUpdatedFileAsyncTask()
{
string key = Path.GetFileNameWithoutExtension(this.CachedPath);
CachedImage cachedImage;
bool isUpdated = false;
if (this.isRemote)
{
if (PersistantDictionary.Instance.TryGetValue(key, out cachedImage))
{
// Can't check the last write time so check to see if the cached image is set to expire
// or if the max age is different.
if (cachedImage.ExpiresUtc < DateTime.UtcNow.AddDays(-MaxFileCachedDuration)
|| cachedImage.MaxAge != MaxFileCachedDuration)
{
if (PersistantDictionary.Instance.TryRemove(key, out cachedImage))
{
isUpdated = true;
}
}
}
else
{
// Nothing in the cache so we should return true.
isUpdated = true;
}
}
// Test now for locally requested files.
if (PersistantDictionary.Instance.TryGetValue(key, out cachedImage))
{
FileInfo imageFileInfo = new FileInfo(this.requestPath);
if (imageFileInfo.Exists)
{
// Check to see if the last write time is different of whether the
// cached image is set to expire or if the max age is different.
if (imageFileInfo.LastWriteTimeUtc != cachedImage.LastWriteTimeUtc
|| cachedImage.ExpiresUtc < DateTime.UtcNow.AddDays(-MaxFileCachedDuration)
|| cachedImage.MaxAge != MaxFileCachedDuration)
{
if (PersistantDictionary.Instance.TryRemove(key, out cachedImage))
{
isUpdated = true;
}
}
}
}
else
{
// Nothing in the cache so we should return true.
isUpdated = true;
}
yield return TaskEx.FromResult(isUpdated);
}
/// <summary>
/// Sets the LastWriteTime of the cached file to match the original file.
/// </summary>
/// <param name="imagePath">
/// The original image path.
/// </param>
/// <param name="cachedImagePath">
/// The cached image path.
/// </param>
/// <param name="isRemote">Whether the file is remote.</param>
/// <returns>
/// The <see cref="IEnumerable{Task}"/>.
/// </returns>
private IEnumerable<Task> SetCachedLastWriteTimeAsyncTask()
{
FileInfo cachedFileInfo = new FileInfo(this.CachedPath);
DateTime lastWriteTime = DateTime.MinValue.ToUniversalTime();
if (isRemote)
{
if (cachedFileInfo.Exists)
{
lastWriteTime = cachedFileInfo.LastWriteTimeUtc;
}
}
else
{
FileInfo imageFileInfo = new FileInfo(this.requestPath);
if (imageFileInfo.Exists && cachedFileInfo.Exists)
{
DateTime dateTime = imageFileInfo.LastWriteTimeUtc;
cachedFileInfo.LastWriteTimeUtc = dateTime;
lastWriteTime = dateTime;
}
}
yield return TaskEx.FromResult(lastWriteTime);
}
/// <summary>
/// Purges any files from the file-system cache in the given folders.
/// </summary>
/// <returns>
/// The <see cref="IEnumerable{Task}"/>.
/// </returns>
private IEnumerable<Task> TrimCachedFoldersAsyncTask()
{
// Group each cache folder and clear any expired items or any that exeed
// the maximum allowable count.
var groups = PersistantDictionary.Instance.ToList()
.GroupBy(x => SubFolderRegex.Match(x.Value.Path).Value)
.Where(g => g.Count() > MaxFilesCount);
foreach (var group in groups)
{
int groupCount = group.Count();
foreach (KeyValuePair<string, CachedImage> pair in group.OrderBy(x => x.Value.ExpiresUtc))
{
// If the group count is equal to the max count minus 1 then we know we
// are counting down from a full directory not simply clearing out
// expired items.
if (groupCount == MaxFilesCount - 1)
{
break;
}
try
{
// Remove from the cache and delete each CachedImage.
FileInfo fileInfo = new FileInfo(pair.Value.Path);
string key = Path.GetFileNameWithoutExtension(fileInfo.Name);
CachedImage cachedImage;
if (PersistantDictionary.Instance.TryRemove(key, out cachedImage))
{
fileInfo.Delete();
groupCount -= 1;
}
}
catch (Exception)
{
// Do Nothing, skip to the next.
// TODO: Should we handle this?
continue;
}
}
}
yield break;
}
/// <summary>
/// Gets the full transformed cached path for the image.
/// The file names are stored as MD5 encrypted versions of the full request path.
/// This should make them unique enough to
/// </summary>
/// <param name="fullPath">The original image path.</param>
/// <param name="imageName">The original image name.</param>
/// <returns>The full cached path for the image.</returns>
private string GetCachePath(string fullPath, string imageName)
{
string cachedPath = string.Empty;
if (AbsoluteCachePath != null)
{
// Use an md5 hash of the full path including the querystring to create the image name.
// That name can also be used as a key for the cached image and we should be able to use
// The first character of that hash as a subfolder.
string parsedExtension = this.ParseExtension(fullPath);
string fallbackExtension = imageName.Substring(imageName.LastIndexOf(".", StringComparison.Ordinal) + 1);
string encryptedName = fullPath.ToMD5Fingerprint();
string subpath = encryptedName.Substring(0, 1);
string cachedFileName = string.Format(
"{0}.{1}",
encryptedName,
!string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension : fallbackExtension);
cachedPath = Path.Combine(AbsoluteCachePath, subpath, cachedFileName);
}
return cachedPath;
}
/// <summary>
/// Returns the correct file extension for the given string input
/// </summary>
/// <param name="input">
/// The string to parse.
/// </param>
/// <returns>
/// The correct file extension for the given string input if it can find one; otherwise an empty string.
/// </returns>
private string ParseExtension(string input)
{
Match match = FormatRegex.Match(input);
return match.Success ? match.Value : string.Empty;
}
#endregion
#endregion
}
}

10
src/ImageProcessor.Web/Caching/CachedImage.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="CachedImage.cs" company="James South"> // <copyright file="CachedImage.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -42,21 +42,21 @@ namespace ImageProcessor.Web.Caching
/// <summary> /// <summary>
/// Gets or sets the value of the cached image. /// Gets or sets the value of the cached image.
/// </summary> /// </summary>
public string Path { get; set; } internal string Path { get; set; }
/// <summary> /// <summary>
/// Gets or sets the maximum age of the cached image in days. /// Gets or sets the maximum age of the cached image in days.
/// </summary> /// </summary>
public int MaxAge { get; set; } internal int MaxAge { get; set; }
/// <summary> /// <summary>
/// Gets or sets the last write time of the cached image. /// Gets or sets the last write time of the cached image.
/// </summary> /// </summary>
public DateTime LastWriteTimeUtc { get; set; } internal DateTime LastWriteTimeUtc { get; set; }
/// <summary> /// <summary>
/// Gets or sets when the cached image should expire from the cache. /// Gets or sets when the cached image should expire from the cache.
/// </summary> /// </summary>
public DateTime ExpiresUtc { get; set; } internal DateTime ExpiresUtc { get; set; }
} }
} }

346
src/ImageProcessor.Web/Caching/Copy of DiskCache.cs

@ -1,346 +0,0 @@
// -----------------------------------------------------------------------
// <copyright file="DiskCache.cs" company="James South">
// Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses.
// </copyright>
// -----------------------------------------------------------------------
namespace ImageProcessor.Web.Caching
{
#region Using
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Web.Hosting;
using ImageProcessor.Helpers.Extensions;
using ImageProcessor.Web.Config;
#endregion
/// <summary>
/// Encapsulates methods to handle disk caching of images.
/// </summary>
internal sealed class DiskCache
{
#region Fields
/// <summary>
/// The maximum number of days to cache files on the system for.
/// </summary>
internal static readonly int MaxFileCachedDuration = ImageProcessorConfig.Instance.MaxCacheDays;
/// <summary>
/// The valid sub directory chars. This used in combination with the file limit per folder
/// allows the storage of 360,000 image files in the cache.
/// </summary>
private const string ValidSubDirectoryChars = "abcdefghijklmnopqrstuvwxyz0123456789";
/// <summary>
/// The maximum number of files allowed in the directory.
/// </summary>
/// <remarks>
/// NTFS directories can handle up to 10,000 files in the directory before slowing down.
/// This will help us to ensure that don't go over that limit.
/// <see cref="http://stackoverflow.com/questions/197162/ntfs-performance-and-large-volumes-of-files-and-directories"/>
/// <see cref="http://stackoverflow.com/questions/115882/how-do-you-deal-with-lots-of-small-files"/>
/// <see cref="http://stackoverflow.com/questions/1638219/millions-of-small-graphics-files-and-how-to-overcome-slow-file-system-access-on"/>
/// </remarks>
private const int MaxFilesCount = 10000;
/// <summary>
/// The regular expression to search strings for file extensions.
/// </summary>
private static readonly Regex FormatRegex = new Regex(
@"(jpeg|png|bmp|gif)", RegexOptions.RightToLeft | RegexOptions.Compiled);
/// <summary>
/// The regular expression to search strings for valid subfolder names.
/// We're specifically not using a shorter regex as we need to be able to iterate through
/// each match group.
/// </summary>
private static readonly Regex SubFolderRegex = new Regex(@"(\/(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9)\/)", RegexOptions.Compiled);
/// <summary>
/// The absolute path to virtual cache path on the server.
/// </summary>
private static readonly string AbsoluteCachePath =
HostingEnvironment.MapPath(ImageProcessorConfig.Instance.VirtualCachePath);
#endregion
#region Methods
/// <summary>
/// The create cache paths.
/// </summary>
/// <returns>
/// The true if the cache directories are created successfully; otherwise, false.
/// </returns>
internal static bool CreateCacheDirectories()
{
try
{
Parallel.ForEach(
ValidSubDirectoryChars.ToCharArray(),
(extension, loop) =>
{
string path = Path.Combine(AbsoluteCachePath, extension.ToString(CultureInfo.InvariantCulture));
DirectoryInfo directoryInfo = new DirectoryInfo(path);
if (!directoryInfo.Exists)
{
directoryInfo.Create();
}
});
}
catch
{
return false;
}
return true;
}
/// <summary>
/// Gets the full transformed cached path for the image.
/// The file names are stored as MD5 encrypted versions of the full request path.
/// This should make them unique enough to
/// </summary>
/// <param name="imagePath">The original image path.</param>
/// <param name="imageName">The original image name.</param>
/// <returns>The full cached path for the image.</returns>
internal static string GetCachePath(string imagePath, string imageName)
{
string cachedPath = string.Empty;
if (AbsoluteCachePath != null)
{
// Use an md5 hash of the full path including the querystring to create the image name.
// That name can also be used as a key for the cached image and we should be able to use
// The first character of that hash as a subfolder.
string parsedExtension = ParseExtension(imagePath);
string fallbackExtension = imageName.Substring(imageName.LastIndexOf(".", StringComparison.Ordinal) + 1);
string encryptedName = imagePath.ToMD5Fingerprint();
string subpath = encryptedName.Substring(0, 1);
string cachedFileName = string.Format(
"{0}.{1}",
encryptedName,
!string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension : fallbackExtension);
cachedPath = Path.Combine(AbsoluteCachePath, subpath, cachedFileName);
}
return cachedPath;
}
/// <summary>
/// Adds an image to the cache.
/// </summary>
/// <param name="cachedPath">
/// The cached path.
/// </param>
/// <param name="lastWriteTimeUtc">
/// The last write time.
/// </param>
internal static void AddImageToCache(string cachedPath, DateTime lastWriteTimeUtc)
{
string key = Path.GetFileNameWithoutExtension(cachedPath);
DateTime expires = DateTime.UtcNow.AddDays(MaxFileCachedDuration).ToUniversalTime();
CachedImage cachedImage = new CachedImage(cachedPath, MaxFileCachedDuration, lastWriteTimeUtc, expires);
PersistantDictionary.Instance.Add(key, cachedImage);
}
/// <summary>
/// Converts an absolute file path
/// </summary>
/// <param name="absolutePath">The absolute path to convert.</param>
/// <param name="request">The <see cref="T:System.Web.HttpRequest"/>from the current context.</param>
/// <returns>The virtual path to the file.</returns>
internal static string GetVirtualPath(string absolutePath, HttpRequest request)
{
string applicationPath = request.PhysicalApplicationPath;
string virtualDir = request.ApplicationPath;
virtualDir = virtualDir == "/" ? virtualDir : (virtualDir + "/");
if (applicationPath != null)
{
return absolutePath.Replace(applicationPath, virtualDir).Replace(@"\", "/");
}
throw new InvalidOperationException("We can only map an absolute back to a relative path if the application path is available.");
}
/// <summary>
/// Returns a value indicating whether the original file has been updated.
/// </summary>
/// <param name="imagePath">The original image path.</param>
/// <param name="cachedImagePath">The cached image path.</param>
/// <param name="isRemote">Whether the file is a remote request.</param>
/// <returns>
/// True if the the original file has been updated; otherwise, false.
/// </returns>
internal static bool IsUpdatedFile(string imagePath, string cachedImagePath, bool isRemote)
{
string key = Path.GetFileNameWithoutExtension(cachedImagePath);
CachedImage cachedImage;
if (isRemote)
{
if (PersistantDictionary.Instance.TryGetValue(key, out cachedImage))
{
// Can't check the last write time so check to see if the cached image is set to expire
// or if the max age is different.
if (cachedImage.ExpiresUtc < DateTime.UtcNow.AddDays(-MaxFileCachedDuration)
|| cachedImage.MaxAge != MaxFileCachedDuration)
{
if (PersistantDictionary.Instance.TryRemove(key, out cachedImage))
{
// We can jump out here.
return true;
}
}
return false;
}
// Nothing in the cache so we should return true.
return true;
}
// Test now for locally requested files.
if (PersistantDictionary.Instance.TryGetValue(key, out cachedImage))
{
FileInfo imageFileInfo = new FileInfo(imagePath);
if (imageFileInfo.Exists)
{
// Check to see if the last write time is different of whether the
// cached image is set to expire or if the max age is different.
if (imageFileInfo.LastWriteTimeUtc != cachedImage.LastWriteTimeUtc
|| cachedImage.ExpiresUtc < DateTime.UtcNow.AddDays(-MaxFileCachedDuration)
|| cachedImage.MaxAge != MaxFileCachedDuration)
{
if (PersistantDictionary.Instance.TryRemove(key, out cachedImage))
{
return true;
}
}
}
}
else
{
// Nothing in the cache so we should return true.
return true;
}
return false;
}
/// <summary>
/// Sets the LastWriteTime of the cached file to match the original file.
/// </summary>
/// <param name="imagePath">
/// The original image path.
/// </param>
/// <param name="cachedImagePath">
/// The cached image path.
/// </param>
/// <param name="isRemote">Whether the file is remote.</param>
/// <returns>
/// The <see cref="System.DateTime"/> set to the last write time of the file.
/// </returns>
internal static DateTime SetCachedLastWriteTime(string imagePath, string cachedImagePath, bool isRemote)
{
FileInfo cachedFileInfo = new FileInfo(cachedImagePath);
if (isRemote)
{
if (cachedFileInfo.Exists)
{
return cachedFileInfo.LastWriteTimeUtc;
}
}
FileInfo imageFileInfo = new FileInfo(imagePath);
if (imageFileInfo.Exists && cachedFileInfo.Exists)
{
DateTime dateTime = imageFileInfo.LastWriteTimeUtc;
cachedFileInfo.LastWriteTimeUtc = dateTime;
return dateTime;
}
return DateTime.MinValue.ToUniversalTime();
}
/// <summary>
/// Purges any files from the file-system cache in the given folders.
/// </summary>
internal static void TrimCachedFolders()
{
// Group each cache folder and clear any expired items or any that exeed
// the maximum allowable count.
var groups = PersistantDictionary.Instance.ToList()
.GroupBy(x => SubFolderRegex.Match(x.Value.Path).Value)
.Where(g => g.Count() > MaxFilesCount);
foreach (var group in groups)
{
int groupCount = group.Count();
foreach (KeyValuePair<string, CachedImage> pair in group.OrderBy(x => x.Value.ExpiresUtc))
{
// If the group count is equal to the max count minus 1 then we know we
// are counting down from a full directory not simply clearing out
// expired items.
if (groupCount == MaxFilesCount - 1)
{
break;
}
try
{
// Remove from the cache and delete each CachedImage.
FileInfo fileInfo = new FileInfo(pair.Value.Path);
string key = Path.GetFileNameWithoutExtension(fileInfo.Name);
CachedImage cachedImage;
if (PersistantDictionary.Instance.TryRemove(key, out cachedImage))
{
fileInfo.Delete();
groupCount -= 1;
}
}
catch (Exception)
{
// Do Nothing, skip to the next.
// TODO: Should we handle this?
continue;
}
}
}
}
/// <summary>
/// Returns the correct file extension for the given string input
/// </summary>
/// <param name="input">
/// The string to parse.
/// </param>
/// <returns>
/// The correct file extension for the given string input if it can find one; otherwise an empty string.
/// </returns>
private static string ParseExtension(string input)
{
Match match = FormatRegex.Match(input);
return match.Success ? match.Value : string.Empty;
}
#endregion
}
}

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

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="DiskCache.cs" company="James South"> // <copyright file="DiskCache.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -10,6 +10,7 @@ namespace ImageProcessor.Web.Caching
#region Using #region Using
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -19,10 +20,11 @@ namespace ImageProcessor.Web.Caching
using System.Web.Hosting; using System.Web.Hosting;
using ImageProcessor.Helpers.Extensions; using ImageProcessor.Helpers.Extensions;
using ImageProcessor.Web.Config; using ImageProcessor.Web.Config;
using ImageProcessor.Web.Helpers;
#endregion #endregion
/// <summary> /// <summary>
/// Encapsulates methods to handle disk caching of images. /// The disk cache.
/// </summary> /// </summary>
internal sealed class DiskCache internal sealed class DiskCache
{ {
@ -61,7 +63,10 @@ namespace ImageProcessor.Web.Caching
/// We're specifically not using a shorter regex as we need to be able to iterate through /// We're specifically not using a shorter regex as we need to be able to iterate through
/// each match group. /// each match group.
/// </summary> /// </summary>
private static readonly Regex SubFolderRegex = new Regex(@"(\/(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9)\/)", RegexOptions.Compiled); private static readonly Regex SubFolderRegex =
new Regex(
@"(\/([a-z]|[0-9])\/(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9)\/)",
RegexOptions.Compiled);
/// <summary> /// <summary>
/// The absolute path to virtual cache path on the server. /// The absolute path to virtual cache path on the server.
@ -69,125 +74,176 @@ namespace ImageProcessor.Web.Caching
private static readonly string AbsoluteCachePath = private static readonly string AbsoluteCachePath =
HostingEnvironment.MapPath(ImageProcessorConfig.Instance.VirtualCachePath); HostingEnvironment.MapPath(ImageProcessorConfig.Instance.VirtualCachePath);
/// <summary>
/// The request for the image.
/// </summary>
private readonly HttpRequest request;
/// <summary>
/// The request path for the image.
/// </summary>
private readonly string requestPath;
/// <summary>
/// The full path for the image.
/// </summary>
private readonly string fullPath;
/// <summary>
/// The image name
/// </summary>
private readonly string imageName;
/// <summary>
/// Whether the request is for a remote image.
/// </summary>
private readonly bool isRemote;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="DiskCache"/> class.
/// </summary>
/// <param name="request">
/// The request for the image.
/// </param>
/// <param name="requestPath">
/// The request path for the image.
/// </param>
/// <param name="fullPath">
/// The full path for the image.
/// </param>
/// <param name="imageName">
/// The image name.
/// </param>
/// <param name="isRemote">
/// Whether the request is for a remote image.
/// </param>
public DiskCache(HttpRequest request, string requestPath, string fullPath, string imageName, bool isRemote)
{
this.request = request;
this.requestPath = requestPath;
this.fullPath = fullPath;
this.imageName = imageName;
this.isRemote = isRemote;
this.CachedPath = this.GetCachePath();
}
#endregion
#region Properties
/// <summary>
/// Gets the cached path.
/// </summary>
internal string CachedPath { get; private set; }
#endregion #endregion
#region Methods #region Methods
#region Internal
/// <summary> /// <summary>
/// The create cache paths. /// Creates the series of directories required to house our cached images.
/// The images are stored in paths that are based upon the MD5 of their full request path
/// taking the first and last characters of the hash to determine their location.
/// <example>~/cache/a/1/ab04g67p91.jpg</example>
/// This allows us to store 36 folders within 36 folders giving us a total of 12,960,000 images.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// The true if the cache directories are created successfully; otherwise, false. /// True if the directories are successfully created; otherwise, false.
/// </returns> /// </returns>
internal static bool CreateCacheDirectories() [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")]
internal static bool CreateDirectories()
{ {
bool success = true;
try try
{ {
// Split up our characters into an array to loop though.
char[] characters = ValidSubDirectoryChars.ToCharArray();
// Loop through and create the first level.
Parallel.ForEach( Parallel.ForEach(
ValidSubDirectoryChars.ToCharArray(), characters,
(extension, loop) => (character, loop) =>
{ {
string path = Path.Combine(AbsoluteCachePath, extension.ToString(CultureInfo.InvariantCulture)); string firstSubPath = Path.Combine(AbsoluteCachePath, character.ToString(CultureInfo.InvariantCulture));
DirectoryInfo directoryInfo = new DirectoryInfo(path); DirectoryInfo directoryInfo = new DirectoryInfo(firstSubPath);
if (!directoryInfo.Exists) if (!directoryInfo.Exists)
{ {
directoryInfo.Create(); directoryInfo.Create();
// Loop through and create the second level.
Parallel.ForEach(
characters,
(subCharacter, subLoop) =>
{
string secondSubPath = Path.Combine(firstSubPath, subCharacter.ToString(CultureInfo.InvariantCulture));
DirectoryInfo subDirectoryInfo = new DirectoryInfo(secondSubPath);
if (!subDirectoryInfo.Exists)
{
subDirectoryInfo.Create();
}
});
} }
}); });
} }
catch catch
{ {
return false; success = false;
} }
return true; return success;
} }
/// <summary> /// <summary>
/// Gets the full transformed cached path for the image. /// Gets the virtual path to the cached processed image.
/// The file names are stored as MD5 encrypted versions of the full request path.
/// This should make them unique enough to
/// </summary> /// </summary>
/// <param name="imagePath">The original image path.</param> /// <returns>The virtual path to the cached processed image.</returns>
/// <param name="imageName">The original image name.</param> internal string GetVirtualCachedPath()
/// <returns>The full cached path for the image.</returns>
internal static string GetCachePath(string imagePath, string imageName)
{ {
string cachedPath = string.Empty; string applicationPath = this.request.PhysicalApplicationPath;
string virtualDir = this.request.ApplicationPath;
virtualDir = virtualDir == "/" ? virtualDir : (virtualDir + "/");
if (AbsoluteCachePath != null) if (applicationPath != null)
{ {
// Use an md5 hash of the full path including the querystring to create the image name. return this.CachedPath.Replace(applicationPath, virtualDir).Replace(@"\", "/");
// That name can also be used as a key for the cached image and we should be able to use
// The first character of that hash as a subfolder.
string parsedExtension = ParseExtension(imagePath);
string fallbackExtension = imageName.Substring(imageName.LastIndexOf(".", StringComparison.Ordinal) + 1);
string encryptedName = imagePath.ToMD5Fingerprint();
string subpath = encryptedName.Substring(0, 1);
string cachedFileName = string.Format(
"{0}.{1}",
encryptedName,
!string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension : fallbackExtension);
cachedPath = Path.Combine(AbsoluteCachePath, subpath, cachedFileName);
} }
return cachedPath; throw new InvalidOperationException(
"We can only map an absolute back to a relative path if the application path is available.");
} }
/// <summary> /// <summary>
/// Adds an image to the cache. /// Adds an image to the cache.
/// </summary> /// </summary>
/// <param name="cachedPath">
/// The cached path.
/// </param>
/// <param name="lastWriteTimeUtc"> /// <param name="lastWriteTimeUtc">
/// The last write time. /// The last write time.
/// </param> /// </param>
internal static void AddImageToCache(string cachedPath, DateTime lastWriteTimeUtc) /// <returns>
/// The <see cref="T:System.Threading.Tasks.Task"/>.
/// </returns>
internal async Task AddImageToCacheAsync(DateTime lastWriteTimeUtc)
{ {
string key = Path.GetFileNameWithoutExtension(cachedPath); string key = Path.GetFileNameWithoutExtension(this.CachedPath);
DateTime expires = DateTime.UtcNow.AddDays(MaxFileCachedDuration).ToUniversalTime(); DateTime expires = DateTime.UtcNow.AddDays(MaxFileCachedDuration).ToUniversalTime();
CachedImage cachedImage = new CachedImage(cachedPath, MaxFileCachedDuration, lastWriteTimeUtc, expires); CachedImage cachedImage = new CachedImage(this.CachedPath, MaxFileCachedDuration, lastWriteTimeUtc, expires);
PersistantDictionary.Instance.Add(key, cachedImage); await PersistantDictionary.Instance.AddAsync(key, cachedImage);
} }
/// <summary> /// <summary>
/// Converts an absolute file path /// Returns a value indicating whether the original file is new or has been updated.
/// </summary> /// </summary>
/// <param name="absolutePath">The absolute path to convert.</param>
/// <param name="request">The <see cref="T:System.Web.HttpRequest"/>from the current context.</param>
/// <returns>The virtual path to the file.</returns>
internal static string GetVirtualPath(string absolutePath, HttpRequest request)
{
string applicationPath = request.PhysicalApplicationPath;
string virtualDir = request.ApplicationPath;
virtualDir = virtualDir == "/" ? virtualDir : (virtualDir + "/");
if (applicationPath != null)
{
return absolutePath.Replace(applicationPath, virtualDir).Replace(@"\", "/");
}
throw new InvalidOperationException("We can only map an absolute back to a relative path if the application path is available.");
}
/// <summary>
/// Returns a value indicating whether the original file has been updated.
/// </summary>
/// <param name="imagePath">The original image path.</param>
/// <param name="cachedImagePath">The cached image path.</param>
/// <param name="isRemote">Whether the file is a remote request.</param>
/// <returns> /// <returns>
/// True if the the original file has been updated; otherwise, false. /// True if the the original file is new or has been updated; otherwise, false.
/// </returns> /// </returns>
internal static bool IsUpdatedFile(string imagePath, string cachedImagePath, bool isRemote) internal async Task<bool> IsNewOrUpdatedFileAsync()
{ {
string key = Path.GetFileNameWithoutExtension(cachedImagePath); string key = Path.GetFileNameWithoutExtension(this.CachedPath);
CachedImage cachedImage; CachedImage cachedImage;
bool isUpdated = false;
if (isRemote) if (this.isRemote)
{ {
if (PersistantDictionary.Instance.TryGetValue(key, out cachedImage)) if (PersistantDictionary.Instance.TryGetValue(key, out cachedImage))
{ {
@ -196,91 +252,114 @@ namespace ImageProcessor.Web.Caching
if (cachedImage.ExpiresUtc < DateTime.UtcNow.AddDays(-MaxFileCachedDuration) if (cachedImage.ExpiresUtc < DateTime.UtcNow.AddDays(-MaxFileCachedDuration)
|| cachedImage.MaxAge != MaxFileCachedDuration) || cachedImage.MaxAge != MaxFileCachedDuration)
{ {
if (PersistantDictionary.Instance.TryRemove(key, out cachedImage)) if (await PersistantDictionary.Instance.TryRemoveAsync(key))
{ {
// We can jump out here. isUpdated = true;
return true;
} }
} }
return false;
} }
else
// Nothing in the cache so we should return true. {
return true; // Nothing in the cache so we should return true.
isUpdated = true;
}
} }
else
// Test now for locally requested files.
if (PersistantDictionary.Instance.TryGetValue(key, out cachedImage))
{ {
FileInfo imageFileInfo = new FileInfo(imagePath); // Test now for locally requested files.
if (PersistantDictionary.Instance.TryGetValue(key, out cachedImage))
if (imageFileInfo.Exists)
{ {
// Check to see if the last write time is different of whether the FileInfo imageFileInfo = new FileInfo(this.requestPath);
// cached image is set to expire or if the max age is different.
if (imageFileInfo.LastWriteTimeUtc != cachedImage.LastWriteTimeUtc if (imageFileInfo.Exists)
|| cachedImage.ExpiresUtc < DateTime.UtcNow.AddDays(-MaxFileCachedDuration)
|| cachedImage.MaxAge != MaxFileCachedDuration)
{ {
if (PersistantDictionary.Instance.TryRemove(key, out cachedImage)) // Check to see if the last write time is different of whether the
// cached image is set to expire or if the max age is different.
if (imageFileInfo.LastWriteTimeUtc != cachedImage.LastWriteTimeUtc
|| cachedImage.ExpiresUtc < DateTime.UtcNow.AddDays(-MaxFileCachedDuration)
|| cachedImage.MaxAge != MaxFileCachedDuration)
{ {
return true; if (await PersistantDictionary.Instance.TryRemoveAsync(key))
{
isUpdated = true;
}
} }
} }
} }
} else
else {
{ // Nothing in the cache so we should return true.
// Nothing in the cache so we should return true. isUpdated = true;
return true; }
} }
return false; return isUpdated;
} }
/// <summary> /// <summary>
/// Sets the LastWriteTime of the cached file to match the original file. /// Sets the LastWriteTime of the cached file to match the original file.
/// </summary> /// </summary>
/// <param name="imagePath">
/// The original image path.
/// </param>
/// <param name="cachedImagePath">
/// The cached image path.
/// </param>
/// <param name="isRemote">Whether the file is remote.</param>
/// <returns> /// <returns>
/// The <see cref="System.DateTime"/> set to the last write time of the file. /// The <see cref="T:System.DateTime"/> set to the last write time of the file.
/// </returns>
internal async Task<DateTime> SetCachedLastWriteTimeAsync()
{
// Create Action delegate for IsNewOrUpdatedFile.
return await TaskHelpers.Run(() => this.SetCachedLastWriteTime());
}
/// <summary>
/// Purges any files from the file-system cache in the given folders.
/// </summary>
/// <returns>
/// The <see cref="T:System.Threading.Tasks.Task"/>.
/// </returns>
internal async Task TrimCachedFoldersAsync()
{
// Create Action delegate for TrimCachedFolders.
await TaskHelpers.Run(this.TrimCachedFolders);
}
#endregion
#region Private
/// <summary>
/// Sets the LastWriteTime of the cached file to match the original file.
/// </summary>
/// <returns>
/// The <see cref="T:System.DateTime"/> of the original and cached file.
/// </returns> /// </returns>
internal static DateTime SetCachedLastWriteTime(string imagePath, string cachedImagePath, bool isRemote) private DateTime SetCachedLastWriteTime()
{ {
FileInfo cachedFileInfo = new FileInfo(cachedImagePath); FileInfo cachedFileInfo = new FileInfo(this.CachedPath);
DateTime lastWriteTime = DateTime.MinValue.ToUniversalTime();
if (isRemote) if (this.isRemote)
{ {
if (cachedFileInfo.Exists) if (cachedFileInfo.Exists)
{ {
return cachedFileInfo.LastWriteTimeUtc; lastWriteTime = cachedFileInfo.LastWriteTimeUtc;
} }
} }
else
FileInfo imageFileInfo = new FileInfo(imagePath);
if (imageFileInfo.Exists && cachedFileInfo.Exists)
{ {
DateTime dateTime = imageFileInfo.LastWriteTimeUtc; FileInfo imageFileInfo = new FileInfo(this.requestPath);
cachedFileInfo.LastWriteTimeUtc = dateTime;
return dateTime; if (imageFileInfo.Exists && cachedFileInfo.Exists)
{
DateTime dateTime = imageFileInfo.LastWriteTimeUtc;
cachedFileInfo.LastWriteTimeUtc = dateTime;
lastWriteTime = dateTime;
}
} }
return DateTime.MinValue.ToUniversalTime(); return lastWriteTime;
} }
/// <summary> /// <summary>
/// Purges any files from the file-system cache in the given folders. /// Purges any files from the file-system cache in the given folders.
/// </summary> /// </summary>
internal static void TrimCachedFolders() private async void TrimCachedFolders()
{ {
// Group each cache folder and clear any expired items or any that exeed // Group each cache folder and clear any expired items or any that exeed
// the maximum allowable count. // the maximum allowable count.
@ -307,24 +386,58 @@ namespace ImageProcessor.Web.Caching
// Remove from the cache and delete each CachedImage. // Remove from the cache and delete each CachedImage.
FileInfo fileInfo = new FileInfo(pair.Value.Path); FileInfo fileInfo = new FileInfo(pair.Value.Path);
string key = Path.GetFileNameWithoutExtension(fileInfo.Name); string key = Path.GetFileNameWithoutExtension(fileInfo.Name);
CachedImage cachedImage;
if (PersistantDictionary.Instance.TryRemove(key, out cachedImage)) if (await PersistantDictionary.Instance.TryRemoveAsync(key))
{ {
fileInfo.Delete(); fileInfo.Delete();
groupCount -= 1; groupCount -= 1;
} }
} }
catch (Exception) // ReSharper disable EmptyGeneralCatchClause
catch
// ReSharper restore EmptyGeneralCatchClause
{ {
// Do Nothing, skip to the next. // Do nothing; skip to the next file.
// TODO: Should we handle this?
continue;
} }
} }
} }
} }
/// <summary>
/// Gets the full transformed cached path for the image.
/// The images are stored in paths that are based upon the MD5 of their full request path
/// taking the first and last characters of the hash to determine their location.
/// <example>~/cache/a/1/ab04g67p91.jpg</example>
/// This allows us to store 36 folders within 36 folders giving us a total of 12,960,000 images.
/// </summary>
/// <returns>The full cached path for the image.</returns>
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")]
private string GetCachePath()
{
string cachedPath = string.Empty;
if (AbsoluteCachePath != null)
{
// Use an md5 hash of the full path including the querystring to create the image name.
// That name can also be used as a key for the cached image and we should be able to use
// The first character of that hash as a subfolder.
string parsedExtension = this.ParseExtension(this.fullPath);
string fallbackExtension = this.imageName.Substring(this.imageName.LastIndexOf(".", StringComparison.Ordinal) + 1);
string encryptedName = this.fullPath.ToMD5Fingerprint();
string firstSubpath = encryptedName.Substring(0, 1);
string secondSubpath = encryptedName.Substring(31, 1);
string cachedFileName = string.Format(
"{0}.{1}",
encryptedName,
!string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension : fallbackExtension);
cachedPath = Path.Combine(AbsoluteCachePath, firstSubpath, secondSubpath, cachedFileName);
}
return cachedPath;
}
/// <summary> /// <summary>
/// Returns the correct file extension for the given string input /// Returns the correct file extension for the given string input
/// </summary> /// </summary>
@ -334,13 +447,13 @@ namespace ImageProcessor.Web.Caching
/// <returns> /// <returns>
/// The correct file extension for the given string input if it can find one; otherwise an empty string. /// The correct file extension for the given string input if it can find one; otherwise an empty string.
/// </returns> /// </returns>
private static string ParseExtension(string input) private string ParseExtension(string input)
{ {
Match match = FormatRegex.Match(input); Match match = FormatRegex.Match(input);
return match.Success ? match.Value : string.Empty; return match.Success ? match.Value : string.Empty;
} }
#endregion
#endregion #endregion
} }
} }

44
src/ImageProcessor.Web/Caching/PersistantDictionary.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="PersistantDictionary.cs" company="James South"> // <copyright file="PersistantDictionary.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -10,9 +10,8 @@ namespace ImageProcessor.Web.Caching
#region Using #region Using
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using ImageProcessor.Web.Helpers; using ImageProcessor.Web.Helpers;
#endregion #endregion
/// <summary> /// <summary>
@ -63,32 +62,24 @@ namespace ImageProcessor.Web.Caching
/// <param name="key"> /// <param name="key">
/// The key of the item to remove. /// The key of the item to remove.
/// </param> /// </param>
/// <param name="value">
/// The value to assign the returned value to.
/// </param>
/// <returns> /// <returns>
/// true if the <see cref="PersistantDictionary"/> removes an element with /// true if the <see cref="PersistantDictionary"/> removes an element with
/// the specified key; otherwise, false. /// the specified key; otherwise, false.
/// </returns> /// </returns>
public bool TryRemove(string key, out CachedImage value) public async Task<bool> TryRemoveAsync(string key)
{ {
// No CachedImage to remove. // No CachedImage to remove.
if (!this.ContainsKey(key)) if (!this.ContainsKey(key))
{ {
value = default(CachedImage);
return false; return false;
} }
// Remove the CachedImage. // Remove the CachedImage.
lock (SyncRoot) CachedImage value = this[key];
{ this.Remove(key);
value = this[key];
this.Remove(key);
this.SaveCache(key, value, true);
return true; await this.SaveCacheAsync(key, value, true);
} return true;
} }
/// <summary> /// <summary>
@ -103,18 +94,15 @@ namespace ImageProcessor.Web.Caching
/// <returns> /// <returns>
/// The value of the item to add or get. /// The value of the item to add or get.
/// </returns> /// </returns>
public new CachedImage Add(string key, CachedImage cachedImage) public async Task<CachedImage> AddAsync(string key, CachedImage cachedImage)
{ {
lock (SyncRoot) // Add the CachedImage.
if (await this.SaveCacheAsync(key, cachedImage, false))
{ {
// Add the CachedImage. this.Add(key, cachedImage);
if (this.SaveCache(key, cachedImage, false))
{
this[key] = cachedImage;
}
return cachedImage;
} }
return cachedImage;
} }
#endregion #endregion
@ -133,16 +121,16 @@ namespace ImageProcessor.Web.Caching
/// <returns> /// <returns>
/// true, if the dictionary is saved to the file-system; otherwise, false. /// true, if the dictionary is saved to the file-system; otherwise, false.
/// </returns> /// </returns>
private bool SaveCache(string key, CachedImage cachedImage, bool remove) private async Task<bool> SaveCacheAsync(string key, CachedImage cachedImage, bool remove)
{ {
try try
{ {
if (remove) if (remove)
{ {
return SQLContext.RemoveImage(key); return await SQLContext.RemoveImageAsync(key);
} }
return SQLContext.AddImage(key, cachedImage); return await SQLContext.AddImageAsync(key, cachedImage);
} }
catch catch
{ {

142
src/ImageProcessor.Web/Caching/SQLContext.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="SQLContext.cs" company="James South"> // <copyright file="SQLContext.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -12,8 +12,11 @@ namespace ImageProcessor.Web.Caching
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.SQLite; using System.Data.SQLite;
using System.IO; using System.IO;
using System.Threading.Tasks;
using System.Web.Hosting; using System.Web.Hosting;
using ImageProcessor.Web.Config; using ImageProcessor.Web.Config;
using ImageProcessor.Web.Helpers;
#endregion #endregion
/// <summary> /// <summary>
@ -21,6 +24,7 @@ namespace ImageProcessor.Web.Caching
/// </summary> /// </summary>
internal sealed class SQLContext internal sealed class SQLContext
{ {
#region Fields
/// <summary> /// <summary>
/// The default path for cached folders on the server. /// The default path for cached folders on the server.
/// </summary> /// </summary>
@ -34,12 +38,15 @@ namespace ImageProcessor.Web.Caching
/// <summary> /// <summary>
/// The connection string. /// The connection string.
/// </summary> /// </summary>
private static readonly string ConnectionString = string.Format("Data Source={0};Version=3;", IndexLocation); private static readonly string ConnectionString = string.Format("Data Source={0};Version=3;", IndexLocation);
#endregion
#region Methods
#region Internal
/// <summary> /// <summary>
/// Creates the database if it doesn't already exist. /// Creates the database if it doesn't already exist.
/// </summary> /// </summary>
public static void CreateDatabase() internal static void CreateDatabase()
{ {
if (!File.Exists(IndexLocation)) if (!File.Exists(IndexLocation))
{ {
@ -84,6 +91,85 @@ namespace ImageProcessor.Web.Caching
} }
} }
/// <summary>
/// Gets all the images from the database.
/// </summary>
/// <returns>
/// The <see cref="System.Collections.Generic.Dictionary{TKey,TVal}"/>.
/// </returns>
internal static Dictionary<string, CachedImage> GetImages()
{
Dictionary<string, CachedImage> dictionary = new Dictionary<string, CachedImage>();
try
{
using (SQLiteConnection connection = new SQLiteConnection(ConnectionString))
{
connection.Open();
using (SQLiteCommand command = new SQLiteCommand(connection))
{
command.CommandText = "SELECT * FROM names;";
SQLiteDataReader reader = command.ExecuteReader();
while (reader.Read())
{
string key = reader["Key"].ToString();
CachedImage image = new CachedImage(
reader["Path"].ToString(),
int.Parse(reader["MaxAge"].ToString()),
DateTime.Parse(reader["LastWriteTimeUtc"].ToString()).ToUniversalTime(),
DateTime.Parse(reader["ExpiresUtc"].ToString()).ToUniversalTime());
dictionary.Add(key, image);
}
}
}
return dictionary;
}
catch
{
return new Dictionary<string, CachedImage>();
}
}
/// <summary>
/// Adds a cached image to the database.
/// </summary>
/// <param name="key">
/// The key for the cached image.
/// </param>
/// <param name="image">
/// The cached image to add.
/// </param>
/// <returns>
/// The true if the addition of the cached image is added; otherwise, false.
/// </returns>
internal static async Task<bool> AddImageAsync(string key, CachedImage image)
{
// Create Action delegate for AddImage.
return await TaskHelpers.Run(() => AddImage(key, image));
}
/// <summary>
/// Removes a cached image from the database.
/// </summary>
/// <param name="key">
/// The key for the cached image.
/// </param>
/// <returns>
/// The true if the addition of the cached image is removed; otherwise, false.
/// </returns>
internal static async Task<bool> RemoveImageAsync(string key)
{
// Create Action delegate for RemoveImage.
return await TaskHelpers.Run(() => RemoveImage(key));
}
#endregion
#region Private
/// <summary> /// <summary>
/// Adds a cached image to the database. /// Adds a cached image to the database.
/// </summary> /// </summary>
@ -96,7 +182,7 @@ namespace ImageProcessor.Web.Caching
/// <returns> /// <returns>
/// The true if the addition of the cached image is added; otherwise, false. /// The true if the addition of the cached image is added; otherwise, false.
/// </returns> /// </returns>
public static bool AddImage(string key, CachedImage image) private static bool AddImage(string key, CachedImage image)
{ {
try try
{ {
@ -144,7 +230,7 @@ namespace ImageProcessor.Web.Caching
/// <returns> /// <returns>
/// The true if the addition of the cached image is removed; otherwise, false. /// The true if the addition of the cached image is removed; otherwise, false.
/// </returns> /// </returns>
public static bool RemoveImage(string key) private static bool RemoveImage(string key)
{ {
try try
{ {
@ -172,49 +258,7 @@ namespace ImageProcessor.Web.Caching
return false; return false;
} }
} }
#endregion
/// <summary> #endregion
/// Gets all the images from the database.
/// </summary>
/// <returns>
/// The <see cref="System.Collections.Generic.Dictionary{TKey,TVal}"/>.
/// </returns>
public static Dictionary<string, CachedImage> GetImages()
{
Dictionary<string, CachedImage> dictionary = new Dictionary<string, CachedImage>();
try
{
using (SQLiteConnection connection = new SQLiteConnection(ConnectionString))
{
connection.Open();
using (SQLiteCommand command = new SQLiteCommand(connection))
{
command.CommandText = "SELECT * FROM names;";
SQLiteDataReader reader = command.ExecuteReader();
while (reader.Read())
{
string key = reader["Key"].ToString();
CachedImage image = new CachedImage(
reader["Path"].ToString(),
int.Parse(reader["MaxAge"].ToString()),
DateTime.Parse(reader["LastWriteTimeUtc"].ToString()).ToUniversalTime(),
DateTime.Parse(reader["ExpiresUtc"].ToString()).ToUniversalTime());
dictionary.Add(key, image);
}
}
}
return dictionary;
}
catch
{
return new Dictionary<string, CachedImage>();
}
}
} }
} }

4
src/ImageProcessor.Web/Config/ImageCacheSection.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ImageCacheSection.cs" company="James South"> // <copyright file="ImageCacheSection.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -15,7 +15,7 @@ namespace ImageProcessor.Web.Config
/// <summary> /// <summary>
/// Represents an image cache section within a configuration file. /// Represents an image cache section within a configuration file.
/// </summary> /// </summary>
public class ImageCacheSection : ConfigurationSection public sealed class ImageCacheSection : ConfigurationSection
{ {
/// <summary> /// <summary>
/// Gets or sets the virtual path of the cache folder. /// Gets or sets the virtual path of the cache folder.

4
src/ImageProcessor.Web/Config/ImageProcessingSection.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ImageProcessingSection.cs" company="James South"> // <copyright file="ImageProcessingSection.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -16,7 +16,7 @@ namespace ImageProcessor.Web.Config
/// Represents an image processing section within a configuration file. /// Represents an image processing section within a configuration file.
/// Nested syntax adapted from <see cref="http://tneustaedter.blogspot.co.uk/2011/09/how-to-create-one-or-more-nested.html"/> /// Nested syntax adapted from <see cref="http://tneustaedter.blogspot.co.uk/2011/09/how-to-create-one-or-more-nested.html"/>
/// </summary> /// </summary>
public class ImageProcessingSection : ConfigurationSection public sealed class ImageProcessingSection : ConfigurationSection
{ {
#region Properties #region Properties
/// <summary> /// <summary>

6
src/ImageProcessor.Web/Config/ImageProcessorConfig.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ImageProcessorConfig.cs" company="James South"> // <copyright file="ImageProcessorConfig.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -18,7 +18,7 @@ namespace ImageProcessor.Web.Config
/// Encapsulates methods to allow the retrieval of ImageProcessor settings. /// Encapsulates methods to allow the retrieval of ImageProcessor settings.
/// <see cref="http://csharpindepth.com/Articles/General/Singleton.aspx"/> /// <see cref="http://csharpindepth.com/Articles/General/Singleton.aspx"/>
/// </summary> /// </summary>
public class ImageProcessorConfig public sealed class ImageProcessorConfig
{ {
#region Fields #region Fields
/// <summary> /// <summary>
@ -111,7 +111,7 @@ namespace ImageProcessor.Web.Config
{ {
get get
{ {
return GetImageSecuritySection().WhiteList.Cast<ImageSecuritySection.SafeURL>().Select(x => x.Url).ToArray(); return GetImageSecuritySection().WhiteList.Cast<ImageSecuritySection.SafeUrl>().Select(x => x.Url).ToArray();
} }
} }

16
src/ImageProcessor.Web/Config/ImageSecuritySection.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ImageSecuritySection.cs" company="James South"> // <copyright file="ImageSecuritySection.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -13,9 +13,9 @@ namespace ImageProcessor.Web.Config
#endregion #endregion
/// <summary> /// <summary>
/// Represents an imagecache section within a configuration file. /// Represents an image security section within a configuration file.
/// </summary> /// </summary>
public class ImageSecuritySection : ConfigurationSection public sealed class ImageSecuritySection : ConfigurationSection
{ {
#region Properties #region Properties
/// <summary> /// <summary>
@ -122,11 +122,11 @@ namespace ImageProcessor.Web.Config
/// </summary> /// </summary>
/// <param name="index">The index of the whitelist item to get.</param> /// <param name="index">The index of the whitelist item to get.</param>
/// <returns>The whitelist item at the given index.</returns> /// <returns>The whitelist item at the given index.</returns>
public SafeURL this[int index] public SafeUrl this[int index]
{ {
get get
{ {
return this.BaseGet(index) as SafeURL; return this.BaseGet(index) as SafeUrl;
} }
set set
@ -148,7 +148,7 @@ namespace ImageProcessor.Web.Config
/// </returns> /// </returns>
protected override ConfigurationElement CreateNewElement() protected override ConfigurationElement CreateNewElement()
{ {
return new SafeURL(); return new SafeUrl();
} }
/// <summary> /// <summary>
@ -158,14 +158,14 @@ namespace ImageProcessor.Web.Config
/// <returns>The element key for a specified whitelist configuration element.</returns> /// <returns>The element key for a specified whitelist configuration element.</returns>
protected override object GetElementKey(ConfigurationElement element) protected override object GetElementKey(ConfigurationElement element)
{ {
return ((SafeURL)element).Url; return ((SafeUrl)element).Url;
} }
} }
/// <summary> /// <summary>
/// Represents a whitelist configuration element within the configuration. /// Represents a whitelist configuration element within the configuration.
/// </summary> /// </summary>
public class SafeURL : ConfigurationElement public class SafeUrl : ConfigurationElement
{ {
/// <summary> /// <summary>
/// Gets or sets the url of the whitelisted file. /// Gets or sets the url of the whitelisted file.

64
src/ImageProcessor.Web/Helpers/AsyncIoExtensions.cs

@ -1,64 +0,0 @@
// License: CPOL at http://www.codeproject.com/info/cpol10.aspx
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace System.IO
{
public static class AsyncIoExtensions
{
public static Task<Stream> GetRequestStreamAsync(this WebRequest webRequest)
{
return Task.Factory.FromAsync(
webRequest.BeginGetRequestStream,
ar => webRequest.EndGetRequestStream(ar),
null);
}
public static Task<WebResponse> GetResponseAsync(this WebRequest webRequest)
{
return Task.Factory.FromAsync(
webRequest.BeginGetResponse,
ar => webRequest.EndGetResponse(ar),
null);
}
public static Task<int> ReadAsync(this Stream input, Byte[] buffer, int offset, int count)
{
return Task.Factory.FromAsync(
input.BeginRead,
(Func<IAsyncResult, int>)input.EndRead,
buffer, offset, count,
null);
}
public static Task WriteAsync(this Stream input, Byte[] buffer, int offset, int count)
{
return Task.Factory.FromAsync(
input.BeginWrite,
input.EndWrite,
buffer, offset, count,
null);
}
public static /*async*/ Task CopyToAsync(this Stream input, Stream output, CancellationToken cancellationToken = default(CancellationToken))
{
return CopyToAsyncTasks(input, output, cancellationToken).ToTask();
}
private static IEnumerable<Task> CopyToAsyncTasks(Stream input, Stream output, CancellationToken cancellationToken)
{
byte[] buffer = new byte[0x1000]; // 4 KiB
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
var readTask = input.ReadAsync(buffer, 0, buffer.Length);
yield return readTask;
if (readTask.Result == 0) break;
cancellationToken.ThrowIfCancellationRequested();
yield return output.WriteAsync(buffer, 0, readTask.Result);
}
}
}
}

347
src/ImageProcessor.Web/Helpers/Copy of RemoteFile.cs

@ -1,347 +0,0 @@
// -----------------------------------------------------------------------
// <copyright file="RemoteFile.cs" company="James South">
// Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses.
// </copyright>
// -----------------------------------------------------------------------
namespace ImageProcessor.Web.Helpers
{
#region Using
using System;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Security;
using System.Text;
using ImageProcessor.Web.Config;
#endregion
/// <summary>
/// Encapsulates methods used to download files from a website address.
/// </summary>
/// <remarks>
/// <para>
/// The purpose of this class is so there's one core way of downloading remote files with url[s] that are from
/// outside users. There's various areas in application where an attacker could supply an external url to the server
/// and tie up resources.
/// </para>
/// For example, the ImageProcessingModule accepts off-server addresses as a path. An attacker could, for instance, pass the url
/// to a file that's a few gigs in size, causing the server to get out-of-memory exceptions or some other errors. An attacker
/// could also use this same method to use one application instance to hammer another site by, again, passing an off-server
/// address of the victims site to the ImageProcessingModule.
/// This class will not throw an exception if the Uri supplied points to a resource local to the running application instance.
/// <para>
/// There shouldn't be any security issues there, as the internal WebRequest instance is still calling it remotely.
/// Any local files that shouldn't be accessed by this won't be allowed by the remote call.
/// </para>
/// Adapted from <see cref="http://blogengine.codeplex.com">BlogEngine.Net</see>
/// </remarks>
internal sealed class RemoteFile
{
#region Fields
/// <summary>
/// The white-list of url[s] from which to download remote files.
/// </summary>
private static readonly Uri[] RemoteFileWhiteList = ImageProcessorConfig.Instance.RemoteFileWhiteList;
/// <summary>
/// The length of time, in milliseconds, that a remote file download attempt can last before timing out.
/// </summary>
private static readonly int TimeoutMilliseconds = ImageProcessorConfig.Instance.Timeout;
/// <summary>
/// The maximum size, in bytes, that a remote file download attempt can download.
/// </summary>
private static readonly int MaxBytes = ImageProcessorConfig.Instance.MaxBytes;
/// <summary>
/// Whether to allow remote downloads.
/// </summary>
private static readonly bool AllowRemoteDownloads = ImageProcessorConfig.Instance.AllowRemoteDownloads;
/// <summary>
/// Whether this RemoteFile instance is ignoring remote download rules set in the current application
/// instance.
/// </summary>
private readonly bool ignoreRemoteDownloadSettings;
/// <summary>
/// The <see cref="T:System.Uri">Uri</see> of the remote file being downloaded.
/// </summary>
private readonly Uri url;
/// <summary>
/// The maximum allowable download size in bytes.
/// </summary>
private readonly int maxDownloadSize;
/// <summary>
/// The length of time, in milliseconds, that a remote file download attempt can last before timing out.
/// </summary>
private int timeoutLength;
/// <summary>
/// The <see cref="T:System.Net.WebResponse">WebResponse</see> object used internally for this RemoteFile instance.
/// </summary>
private WebRequest webRequest;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="T:ImageProcessor.Web.Helpers.RemoteFile">RemoteFile</see> class.
/// </summary>
/// <param name="filePath">The url of the file to be downloaded.</param>
/// <param name="ignoreRemoteDownloadSettings">
/// If set to <see langword="true"/>, then RemoteFile should ignore the current the applications instance's remote download settings; otherwise,<see langword="false"/>.
/// </param>
internal RemoteFile(Uri filePath, bool ignoreRemoteDownloadSettings)
{
Contract.Requires(filePath != null);
this.url = filePath;
this.ignoreRemoteDownloadSettings = ignoreRemoteDownloadSettings;
this.timeoutLength = TimeoutMilliseconds;
this.maxDownloadSize = MaxBytes;
}
#endregion
#region Properties
/// <summary>
/// Gets a value indicating whether this RemoteFile instance is ignoring remote download rules set in the
/// current application instance.
/// <remarks>
/// This should only be set to true if the supplied url is a verified resource. Use at your own risk.
/// </remarks>
/// </summary>
/// <value>
/// <see langword="true"/> if this RemoteFile instance is ignoring remote download rules set in the current
/// application instance; otherwise, <see langword="false"/>.
/// </value>
public bool IgnoreRemoteDownloadSettings
{
get
{
return this.ignoreRemoteDownloadSettings;
}
}
/// <summary>
/// Gets the Uri of the remote file being downloaded.
/// </summary>
public Uri Uri
{
get
{
return this.url;
}
}
/// <summary>
/// Gets or sets the length of time, in milliseconds, that a remote file download attempt can
/// last before timing out.
/// <remarks>
/// <para>
/// This value can only be set if the instance is supposed to ignore the remote download settings set
/// in the current application instance.
/// </para>
/// <para>
/// Set this value to 0 if there should be no timeout.
/// </para>
/// </remarks>
/// </summary>
public int TimeoutLength
{
get
{
return this.IgnoreRemoteDownloadSettings ? this.timeoutLength : TimeoutMilliseconds;
}
set
{
if (!this.IgnoreRemoteDownloadSettings)
{
throw new SecurityException("Timeout length can not be adjusted on remote files that are abiding by remote download rules");
}
if (value < 0)
{
throw new ArgumentOutOfRangeException("TimeoutLength");
}
this.timeoutLength = value;
}
}
/// <summary>
/// Gets or sets the maximum download size, in bytes, that a remote file download attempt can be.
/// <remarks>
/// <para>
/// This value can only be set if the instance is supposed to ignore the remote download settings set
/// in the current application instance.
/// </para>
/// <para>
/// Set this value to 0 if there should be no timeout.
/// </para>
/// </remarks>
/// </summary>
public int MaxDownloadSize
{
get
{
return this.IgnoreRemoteDownloadSettings ? this.maxDownloadSize : MaxBytes;
}
set
{
if (!this.IgnoreRemoteDownloadSettings)
{
throw new SecurityException("Max Download Size can not be adjusted on remote files that are abiding by remote download rules");
}
if (value < 0)
{
throw new ArgumentOutOfRangeException("MaxDownloadSize");
}
this.timeoutLength = value;
}
}
#endregion
#region Methods
#region Public
/// <summary>
/// Returns the <see cref="T:System.Net.WebResponse">WebResponse</see> used to download this file.
/// <remarks>
/// <para>
/// This method is meant for outside users who need specific access to the WebResponse this class
/// generates. They're responsible for disposing of it.
/// </para>
/// </remarks>
/// </summary>
/// <returns>The <see cref="T:System.Net.WebResponse">WebResponse</see> used to download this file.</returns>
public WebResponse GetWebResponse()
{
WebResponse response = this.GetWebRequest().GetResponse();
long contentLength = response.ContentLength;
// WebResponse.ContentLength doesn't always know the value, it returns -1 in this case.
if (contentLength == -1)
{
// 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.");
}
return response;
}
/// <summary>
/// Returns the remote file as a String.
/// <remarks>
/// This returns the resulting stream as a string as passed through a StreamReader.
/// </remarks>
/// </summary>
/// <returns>The remote file as a String.</returns>
public string GetFileAsString()
{
using (WebResponse response = this.GetWebResponse())
{
Stream responseStream = response.GetResponseStream();
if (responseStream != null)
{
// Pipe the stream to a stream reader with the required encoding format.
using (StreamReader reader = new StreamReader(responseStream, Encoding.UTF8))
{
return reader.ReadToEnd();
}
}
return string.Empty;
}
}
#endregion
#region Private
/// <summary>
/// Performs a check to see whether the application is able to download remote files.
/// </summary>
private void CheckCanDownload()
{
if (!this.IgnoreRemoteDownloadSettings && !AllowRemoteDownloads)
{
throw new SecurityException("application is not configured to allow remote file downloads.");
}
}
/// <summary>
/// Creates the WebRequest object used internally for this RemoteFile instance.
/// </summary>
/// <returns>
/// <para>
/// The WebRequest should not be passed outside of this instance, as it will allow tampering. Anyone
/// that needs more fine control over the downloading process should probably be using the WebRequest
/// class on its own.
/// </para>
/// </returns>
private WebRequest GetWebRequest()
{
// Check downloads are allowed.
this.CheckCanDownload();
// Check the url is from a whitelisted location.
this.CheckSafeUrlLocation();
if (this.webRequest == null)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.Uri);
request.Headers["Accept-Encoding"] = "gzip";
request.Headers["Accept-Language"] = "en-us";
request.Credentials = CredentialCache.DefaultNetworkCredentials;
request.AutomaticDecompression = DecompressionMethods.GZip;
if (this.TimeoutLength > 0)
{
request.Timeout = this.TimeoutLength;
}
this.webRequest = request;
}
return this.webRequest;
}
/// <summary>
/// Returns a value indicating whether the current url is in a list of safe download locations.
/// </summary>
private void CheckSafeUrlLocation()
{
bool validUrl = RemoteFileWhiteList.Any(item => item.Host.ToUpperInvariant().Equals(this.url.Host.ToUpperInvariant()));
if (!validUrl)
{
throw new SecurityException("application is not configured to allow remote file downloads from this domain.");
}
}
#endregion
#endregion
}
}

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

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="LockedDictionary.cs" company="James South"> // <copyright file="LockedDictionary.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

52
src/ImageProcessor.Web/Helpers/ObjectFactory.cs

@ -1,52 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ImageProcessor.Web.Helpers
{
using System.Linq.Expressions;
using System.Reflection;
public class ObjectFactory
{
public delegate T ObjectActivator<out T>(params object[] args);
public static ObjectActivator<T> GetActivator<T>(ConstructorInfo ctor)
{
Type type = ctor.DeclaringType;
ParameterInfo[] paramsInfo = ctor.GetParameters();
// Create a single param of type object[]
ParameterExpression param = Expression.Parameter(typeof(object[]), "args");
Expression[] argsExp = new Expression[paramsInfo.Length];
// Pick each arg from the params array
// and create a typed expression for them
for (int i = 0; i < paramsInfo.Length; i++)
{
Expression index = Expression.Constant(i);
Type paramType = paramsInfo[i].ParameterType;
Expression paramAccessorExp = Expression.ArrayIndex(param, index);
Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);
argsExp[i] = paramCastExp;
}
// Make a NewExpression that calls the
// ctor with the args we just created
NewExpression newExp = Expression.New(ctor, argsExp);
// Create a lambda with the New
// Expression as body and our param object[] as arg
LambdaExpression lambda = Expression.Lambda(typeof(ObjectActivator<T>), newExp, param);
// Compile it
ObjectActivator<T> compiled = (ObjectActivator<T>)lambda.Compile();
return compiled;
}
}
}

20
src/ImageProcessor.Web/Helpers/ProcessorFactory.cs

@ -1,20 +0,0 @@

namespace ImageProcessor.Web.Helpers
{
using System;
using System.Linq.Expressions;
using ImageProcessor.Processors;
public static class ProcessorFactory
{
public static T New<T>() where T:IGraphicsProcessor
{
Type t = typeof(T);
Func<T> method = Expression.Lambda<Func<T>>(Expression.Block(t, new Expression[] { Expression.New(t) })).Compile();
return method();
}
}
}

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

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="RemoteFile.cs" company="James South"> // <copyright file="RemoteFile.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -9,16 +9,15 @@ namespace ImageProcessor.Web.Helpers
{ {
#region Using #region Using
using System; using System;
using System.Diagnostics.Contracts; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Security; using System.Security;
using System.Text; using System.Text;
using ImageProcessor.Web.Config;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Generic; using ImageProcessor.Web.Config;
#endregion #endregion
/// <summary> /// <summary>
@ -231,9 +230,32 @@ namespace ImageProcessor.Web.Helpers
/// <returns> /// <returns>
/// The <see cref="IEnumerable{Task}"/>. /// The <see cref="IEnumerable{Task}"/>.
/// </returns> /// </returns>
internal /*async*/ Task<WebResponse> GetWebResponseAsync() internal async Task<WebResponse> GetWebResponseAsync()
{ {
return this.GetWebResponseAsyncTask().ToTask<WebResponse>(); WebResponse response = await this.GetWebRequest().GetResponseAsync();
long contentLength = response.ContentLength;
// WebResponse.ContentLength doesn't always know the value, it returns -1 in this case.
if (contentLength == -1)
{
// 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.");
}
return response;
} }
/// <summary> /// <summary>
@ -243,7 +265,7 @@ namespace ImageProcessor.Web.Helpers
/// </remarks> /// </remarks>
/// </summary> /// </summary>
/// <returns>The remote file as a String.</returns> /// <returns>The remote file as a String.</returns>
public string GetFileAsString() internal string GetFileAsString()
{ {
Task<WebResponse> responseTask = this.GetWebResponseAsync(); Task<WebResponse> responseTask = this.GetWebResponseAsync();
@ -266,49 +288,6 @@ namespace ImageProcessor.Web.Helpers
#endregion #endregion
#region Private #region Private
/// <summary>
/// Returns the <see cref="T:System.Net.WebResponse">WebResponse</see> used to download this file.
/// <remarks>
/// <para>
/// This method is meant for outside users who need specific access to the WebResponse this class
/// generates. They're responsible for disposing of it.
/// </para>
/// </remarks>
/// </summary>
/// <returns>
/// The <see cref="IEnumerable{Task}"/>.
/// </returns>
private IEnumerable<Task> GetWebResponseAsyncTask()
{
Task<WebResponse> responseTask = this.GetWebRequest().GetResponseAsync();
yield return responseTask;
WebResponse response = responseTask.Result;
long contentLength = response.ContentLength;
// WebResponse.ContentLength doesn't always know the value, it returns -1 in this case.
if (contentLength == -1)
{
// 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.");
}
yield return TaskEx.FromResult(response);
}
/// <summary> /// <summary>
/// Performs a check to see whether the application is able to download remote files. /// Performs a check to see whether the application is able to download remote files.
/// </summary> /// </summary>
@ -373,5 +352,3 @@ namespace ImageProcessor.Web.Helpers
#endregion #endregion
} }
} }

174
src/ImageProcessor.Web/Helpers/TaskEx.cs

@ -1,174 +0,0 @@
// License: CPOL at http://www.codeproject.com/info/cpol10.aspx
namespace System.Threading.Tasks
{
using System.Collections.Generic;
/// <summary>
/// Extensions related to the <see cref="Task"/> classes.
/// Supports implementing "async"-style methods in C#4 using iterators.
/// </summary>
/// <remarks>
/// I would call this TaskExtensions, except that clients must name the class to use methods like <see cref="FromResult{T}(T)"/>.
/// Based on work from Await Tasks in C#4 using Iterators by Keith L Robertson.
/// <see cref="http://www.codeproject.com/Articles/504197/Await-Tasks-in-Csharp4-using-Iterators"/>
/// </remarks>
public static class TaskEx
{
/// <summary>
/// Return a Completed <see cref="Task{TResult}"/> with a specific <see cref="Task{TResult}.Result"/> value.
/// </summary>
/// <typeparam name="TResult">
/// The result
/// </typeparam>
/// <param name="resultValue">
/// The result Value.
/// </param>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public static Task<TResult> FromResult<TResult>(TResult resultValue)
{
var completionSource = new TaskCompletionSource<TResult>();
completionSource.SetResult(resultValue);
return completionSource.Task;
}
/// <summary>
/// Transform an enumeration of <see cref="Task"/> into a single non-Result <see cref="Task"/>.
/// </summary>
/// <param name="tasks">
/// The tasks.
/// </param>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public static Task ToTask(this IEnumerable<Task> tasks)
{
return ToTask<VoidResult>(tasks);
}
/// <summary>
/// Transform an enumeration of <see cref="Task"/> into a single <see cref="Task{TResult}"/>.
/// The final <see cref="Task"/> in <paramref name="tasks"/> must be a <see cref="Task{TResult}"/>.
/// </summary>
/// <typeparam name="TResult">
/// The task results
/// </typeparam>
/// <param name="tasks">
/// The tasks.
/// </param>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public static Task<TResult> ToTask<TResult>(this IEnumerable<Task> tasks)
{
var taskScheduler =
SynchronizationContext.Current == null
? TaskScheduler.Default : TaskScheduler.FromCurrentSynchronizationContext();
var taskEnumerator = tasks.GetEnumerator();
var completionSource = new TaskCompletionSource<TResult>();
// Clean up the enumerator when the task completes.
completionSource.Task.ContinueWith(t => taskEnumerator.Dispose(), taskScheduler);
ToTaskDoOneStep(taskEnumerator, taskScheduler, completionSource, null);
return completionSource.Task;
}
/// <summary>
/// If the previous task Canceled or Faulted, complete the master task with the same <see cref="Task.Status"/>.
/// Obtain the next <see cref="Task"/> from the <paramref name="taskEnumerator"/>.
/// If none, complete the master task, possibly with the <see cref="Task{T}.Result"/> of the last task.
/// Otherwise, set up the task with a continuation to come do this again when it completes.
/// </summary>
private static void ToTaskDoOneStep<TResult>(
IEnumerator<Task> taskEnumerator, TaskScheduler taskScheduler,
TaskCompletionSource<TResult> completionSource, Task completedTask)
{
// Check status of previous nested task (if any), and stop if Canceled or Faulted.
TaskStatus status;
if (completedTask == null)
{
// This is the first task from the iterator; skip status check.
}
else if ((status = completedTask.Status) == TaskStatus.Canceled)
{
completionSource.SetCanceled();
return;
}
else if (status == TaskStatus.Faulted)
{
completionSource.SetException(completedTask.Exception);
return;
}
// Check for cancellation before looking for the next task.
// This causes a problem where the ultimate Task does not complete and fire any continuations; I don't know why.
// So cancellation from the Token must be handled within the iterator itself.
//if (cancellationToken.IsCancellationRequested) {
// completionSource.SetCanceled();
// return;
//}
// Find the next Task in the iterator; handle cancellation and other exceptions.
Boolean haveMore;
try
{
haveMore = taskEnumerator.MoveNext();
}
catch (OperationCanceledException cancExc)
{
//if (cancExc.CancellationToken == cancellationToken) completionSource.SetCanceled();
//else completionSource.SetException(cancExc);
completionSource.SetCanceled();
return;
}
catch (Exception exc)
{
completionSource.SetException(exc);
return;
}
if (!haveMore)
{
// No more tasks; set the result from the last completed task (if any, unless no result is requested).
// We know it's not Canceled or Faulted because we checked at the start of this method.
if (typeof(TResult) == typeof(VoidResult))
{ // No result
completionSource.SetResult(default(TResult));
}
else if (!(completedTask is Task<TResult>))
{ // Wrong result
completionSource.SetException(new InvalidOperationException(
"Asynchronous iterator " + taskEnumerator +
" requires a final result task of type " + typeof(Task<TResult>).FullName +
(completedTask == null ? ", but none was provided." :
"; the actual task type was " + completedTask.GetType().FullName)));
}
else
{
completionSource.SetResult(((Task<TResult>)completedTask).Result);
}
}
else
{
// When the nested task completes, continue by performing this function again.
// Note: This is NOT a recursive call; the current method activation will complete
// almost immediately and independently of the lambda continuation.
taskEnumerator.Current.ContinueWith(
nextTask => ToTaskDoOneStep(taskEnumerator, taskScheduler, completionSource, nextTask),
taskScheduler);
}
}
/// <summary>
/// Internal marker type for using <see cref="ToTask{T}"/> to implement <see cref="ToTask"/>.
/// </summary>
private abstract class VoidResult
{
}
}
}

52
src/ImageProcessor.Web/Helpers/TaskHelpers.cs

@ -0,0 +1,52 @@
// -----------------------------------------------------------------------
// <copyright file="TaskHelpers.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// -----------------------------------------------------------------------
namespace ImageProcessor.Web.Helpers
{
#region Using
using System;
using System.Threading.Tasks;
#endregion
/// <summary>
/// Provides some syntactic sugar to run tasks.
/// </summary>
public sealed class TaskHelpers
{
/// <summary>
/// Queues the specified work to run on the ThreadPool and returns a Task handle for that work.
/// </summary>
/// <param name="action">The work to execute asynchronously</param>
/// <returns>A Task that represents the work queued to execute in the ThreadPool.</returns>
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="action"/> parameter was null.
/// </exception>
public static Task Run(Action action)
{
Task task = new Task(action);
task.Start();
return task;
}
/// <summary>
/// Queues the specified work to run on the ThreadPool and returns a proxy for the
/// Task(TResult) returned by <paramref name="function"/>.
/// </summary>
/// <typeparam name="TResult">The type of the result returned by the proxy Task.</typeparam>
/// <param name="function">The work to execute asynchronously</param>
/// <returns>A Task(TResult) that represents a proxy for the Task(TResult) returned by <paramref name="function"/>.</returns>
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="function"/> parameter was null.
/// </exception>
public static Task<TResult> Run<TResult>(Func<TResult> function)
{
Task<TResult> task = new Task<TResult>(function);
task.Start();
return task;
}
}
}

342
src/ImageProcessor.Web/HttpModules/Copy of ImageProcessingModule.cs

@ -1,342 +0,0 @@
// -----------------------------------------------------------------------
// <copyright file="ImageProcessingModule.cs" company="James South">
// Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses.
// </copyright>
// -----------------------------------------------------------------------
namespace ImageProcessor.Web.HttpModules
{
#region Using
using System;
using System.IO;
using System.Net;
using System.Reflection;
using System.Web;
using System.Web.Hosting;
using ImageProcessor.Helpers.Extensions;
using ImageProcessor.Imaging;
using ImageProcessor.Web.Caching;
using ImageProcessor.Web.Config;
using ImageProcessor.Web.Helpers;
#endregion
/// <summary>
/// Processes any image requests within the web application.
/// </summary>
public class ImageProcessingModule : IHttpModule
{
#region Fields
/// <summary>
/// The key for storing the response type of the current image.
/// </summary>
private const string CachedResponseTypeKey = "CACHED_IMAGE_RESPONSE_TYPE";
/// <summary>
/// The value to prefix any remote image requests with to ensure they get captured.
/// </summary>
private static readonly string RemotePrefix = ImageProcessorConfig.Instance.RemotePrefix;
/// <summary>
/// The object to lock against.
/// </summary>
private static readonly object SyncRoot = new object();
/// <summary>
/// The assembly version.
/// </summary>
private static readonly string AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
/// <summary>
/// A value indicating whether the application has started.
/// </summary>
private static bool hasModuleInitialized;
#endregion
/// <summary>
/// The delegate void representing the ProcessImage method.
/// </summary>
/// <param name="context">
/// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides
/// references to the intrinsic server objects
/// </param>
private delegate void ProcessImageDelegate(HttpContext context);
#region IHttpModule Members
/// <summary>
/// Initializes a module and prepares it to handle requests.
/// </summary>
/// <param name="context">
/// An <see cref="T:System.Web.HttpApplication"/> that provides
/// access to the methods, properties, and events common to all
/// application objects within an ASP.NET application
/// </param>
public void Init(HttpApplication context)
{
if (!hasModuleInitialized)
{
lock (SyncRoot)
{
if (!hasModuleInitialized)
{
DiskCache.CreateCacheDirectories();
hasModuleInitialized = true;
}
}
}
context.AddOnBeginRequestAsync(this.OnBeginAsync, this.OnEndAsync);
context.PreSendRequestHeaders += this.ContextPreSendRequestHeaders;
}
/// <summary>
/// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.
/// </summary>
public void Dispose()
{
// Nothing to dispose.
}
#endregion
/// <summary>
/// The <see cref="T:System.Web.BeginEventHandler"/> that starts asynchronous processing
/// of the <see cref="System.Web.HttpApplication.BeginRequest"/>.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// An <see cref="T:System.EventArgs">EventArgs</see> that contains
/// the event data.
/// </param>
/// <param name="callBack">
/// The delegate to call when the asynchronous method call is complete.
/// If the callback is null, the delegate is not called.
/// </param>
/// <param name="state">
/// Any additional data needed to process the request.
/// </param>
/// <returns>
/// The status of the asynchronous operation.
/// </returns>
private IAsyncResult OnBeginAsync(object sender, EventArgs e, AsyncCallback callBack, object state)
{
HttpContext context = ((HttpApplication)sender).Context;
ProcessImageDelegate processImage = this.ProcessImage;
return processImage.BeginInvoke(context, callBack, state);
}
/// <summary>
/// The method that handles asynchronous events such as application events.
/// </summary>
/// <param name="result">
/// The <see cref="T:System.IAsyncResult"/> that is the result of the
/// <see cref="T:System.Web.BeginEventHandler"/> operation.
/// </param>
private void OnEndAsync(IAsyncResult result)
{
// Ensure our ProcessImage has completed in the background.
while (!result.IsCompleted)
{
System.Threading.Thread.Sleep(1);
}
}
/// <summary>
/// Occurs just before ASP.NET send HttpHeaders to the client.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">An <see cref="T:System.EventArgs">EventArgs</see> that contains the event data.</param>
private void ContextPreSendRequestHeaders(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
object responseTypeObject = context.Items[CachedResponseTypeKey];
if (responseTypeObject != null)
{
string responseType = (string)responseTypeObject;
// Set the headers
this.SetHeaders(context, responseType);
context.Items[CachedResponseTypeKey] = null;
}
}
#region Private
/// <summary>
/// Processes the image.
/// </summary>
/// <param name="context">
/// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides
/// references to the intrinsic server objects
/// </param>
private void ProcessImage(HttpContext context)
{
// Is this a remote file.
bool isRemote = context.Request.Path.Equals(RemotePrefix, StringComparison.OrdinalIgnoreCase);
string path = string.Empty;
string queryString = string.Empty;
if (isRemote)
{
// We need to split the querystring to get the actual values we want.
string urlDecode = HttpUtility.UrlDecode(context.Request.QueryString.ToString());
if (urlDecode != null)
{
string[] paths = urlDecode.Split('?');
path = paths[0];
if (paths.Length > 1)
{
queryString = paths[1];
}
}
}
else
{
path = HostingEnvironment.MapPath(context.Request.Path);
queryString = HttpUtility.UrlDecode(context.Request.QueryString.ToString());
}
// Only process requests that pass our sanitizing filter.
if (ImageUtils.IsValidImageExtension(path) && !string.IsNullOrWhiteSpace(queryString))
{
if (this.FileExists(path, isRemote))
{
string fullPath = string.Format("{0}?{1}", path, queryString);
string imageName = Path.GetFileName(path);
string cachedPath = DiskCache.GetCachePath(fullPath, imageName);
bool isUpdated = DiskCache.IsUpdatedFile(path, cachedPath, isRemote);
// Only process if the file has been updated.
if (isUpdated)
{
// Process the image.
using (ImageFactory imageFactory = new ImageFactory())
{
if (isRemote)
{
Uri uri = new Uri(path);
RemoteFile remoteFile = new RemoteFile(uri, false);
using (MemoryStream memoryStream = new MemoryStream())
{
using (Stream responseStream = remoteFile.GetWebResponse().GetResponseStream())
{
if (responseStream != null)
{
//lock (SyncRoot)
//{
// Trim the cache.
DiskCache.TrimCachedFolders();
responseStream.CopyTo(memoryStream);
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);
// Add to the cache.
DiskCache.AddImageToCache(cachedPath, dateTime);
//}
}
}
}
}
else
{
//lock (SyncRoot)
//{
// Trim the cache.
DiskCache.TrimCachedFolders();
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);
// Add to the cache.
DiskCache.AddImageToCache(cachedPath, dateTime);
//}
}
}
}
context.Items[CachedResponseTypeKey] = ImageUtils.GetResponseType(imageName).ToDescription();
// The cached file is valid so just rewrite the path.
context.RewritePath(DiskCache.GetVirtualPath(cachedPath, context.Request), false);
}
}
}
/// <summary>
/// returns a value indicating whether a file exists.
/// </summary>
/// <param name="path">The path to the file to check.</param>
/// <param name="isRemote">Whether the file is remote.</param>
/// <returns>True if the file exists, otherwise false.</returns>
/// <remarks>If the file is remote the method will always return true.</remarks>
private bool FileExists(string path, bool isRemote)
{
if (isRemote)
{
return true;
}
FileInfo fileInfo = new FileInfo(path);
return fileInfo.Exists;
}
/// <summary>
/// This will make the browser and server keep the output
/// in its cache and thereby improve performance.
/// See http://en.wikipedia.org/wiki/HTTP_ETag
/// </summary>
/// <param name="context">
/// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides
/// references to the intrinsic server objects
/// </param>
/// <param name="responseType">The HTTP MIME type to to send.</param>
private void SetHeaders(HttpContext context, string responseType)
{
HttpResponse response = context.Response;
response.ContentType = responseType;
response.AddHeader("Image-Served-By", "ImageProcessor/" + AssemblyVersion);
HttpCachePolicy cache = response.Cache;
cache.VaryByHeaders["Accept-Encoding"] = true;
int maxDays = DiskCache.MaxFileCachedDuration;
cache.SetExpires(DateTime.Now.ToUniversalTime().AddDays(maxDays));
cache.SetMaxAge(new TimeSpan(maxDays, 0, 0, 0));
cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
string incomingEtag = context.Request.Headers["If-None-Match"];
cache.SetCacheability(HttpCacheability.Public);
if (incomingEtag == null)
{
return;
}
response.Clear();
response.StatusCode = (int)HttpStatusCode.NotModified;
response.SuppressContent = true;
}
#endregion
}
}

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

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ImageProcessingModule.cs" company="James South"> // <copyright file="ImageProcessingModule.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -12,6 +12,8 @@ namespace ImageProcessor.Web.HttpModules
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Web; using System.Web;
using System.Web.Hosting; using System.Web.Hosting;
using ImageProcessor.Helpers.Extensions; using ImageProcessor.Helpers.Extensions;
@ -19,20 +21,18 @@ namespace ImageProcessor.Web.HttpModules
using ImageProcessor.Web.Caching; using ImageProcessor.Web.Caching;
using ImageProcessor.Web.Config; using ImageProcessor.Web.Config;
using ImageProcessor.Web.Helpers; using ImageProcessor.Web.Helpers;
using System.Threading.Tasks;
using System.Collections.Generic;
#endregion #endregion
/// <summary> /// <summary>
/// Processes any image requests within the web application. /// Processes any image requests within the web application.
/// </summary> /// </summary>
public class ImageProcessingModule : IHttpModule public sealed class ImageProcessingModule : IHttpModule
{ {
#region Fields #region Fields
/// <summary> /// <summary>
/// The key for storing the response type of the current image. /// The key for storing the response type of the current image.
/// </summary> /// </summary>
private const string CachedResponseTypeKey = "CACHED_IMAGE_RESPONSE_TYPE"; private const string CachedResponseTypeKey = "CACHED_IMAGE_RESPONSE_TYPE_054F217C-11CF-49FF-8D2F-698E8E6EB58F";
/// <summary> /// <summary>
/// The value to prefix any remote image requests with to ensure they get captured. /// The value to prefix any remote image requests with to ensure they get captured.
@ -40,19 +40,19 @@ namespace ImageProcessor.Web.HttpModules
private static readonly string RemotePrefix = ImageProcessorConfig.Instance.RemotePrefix; private static readonly string RemotePrefix = ImageProcessorConfig.Instance.RemotePrefix;
/// <summary> /// <summary>
/// The object to lock against. /// The assembly version.
/// </summary> /// </summary>
private static readonly object SyncRoot = new object(); private static readonly string AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
/// <summary> /// <summary>
/// The assembly version. /// The value that acts as a basis to check that the startup code has only been ran once.
/// </summary> /// </summary>
private static readonly string AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); private static int initCheck;
/// <summary> /// <summary>
/// A value indicating whether the application has started. /// A value indicating whether the application has started.
/// </summary> /// </summary>
private static bool hasModuleInitialized; private readonly bool hasModuleInitialized = initCheck == 1;
#endregion #endregion
#region IHttpModule Members #region IHttpModule Members
@ -66,17 +66,11 @@ namespace ImageProcessor.Web.HttpModules
/// </param> /// </param>
public void Init(HttpApplication context) public void Init(HttpApplication context)
{ {
if (!hasModuleInitialized) if (!this.hasModuleInitialized)
{ {
lock (SyncRoot) Interlocked.CompareExchange(ref initCheck, 1, 0);
{
if (!hasModuleInitialized) DiskCache.CreateDirectories();
{
Cache.CreateDirectoriesAsync();
//DiskCache.CreateCacheDirectories();
hasModuleInitialized = true;
}
}
} }
context.BeginRequest += this.ContextBeginRequest; context.BeginRequest += this.ContextBeginRequest;
@ -97,10 +91,10 @@ namespace ImageProcessor.Web.HttpModules
/// </summary> /// </summary>
/// <param name="sender">The source of the event.</param> /// <param name="sender">The source of the event.</param>
/// <param name="e">An <see cref="T:System.EventArgs">EventArgs</see> that contains the event data.</param> /// <param name="e">An <see cref="T:System.EventArgs">EventArgs</see> that contains the event data.</param>
private void ContextBeginRequest(object sender, EventArgs e) private async void ContextBeginRequest(object sender, EventArgs e)
{ {
HttpContext context = ((HttpApplication)sender).Context; HttpContext context = ((HttpApplication)sender).Context;
this.ProcessImage(context); await this.ProcessImageAsync(context);
} }
/// <summary> /// <summary>
@ -126,30 +120,6 @@ namespace ImageProcessor.Web.HttpModules
} }
#region Private #region Private
/// <summary>
/// Processes the image.
/// </summary>
/// <param name="context">
/// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides
/// references to the intrinsic server objects
/// </param>
private void ProcessImage(HttpContext context)
{
this.ProcessImageAsync(context);
}
/// <summary>
/// Processes the image.
/// </summary>
/// <param name="context">
/// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides
/// references to the intrinsic server objects
/// </param>
private /*async*/ Task ProcessImageAsync(HttpContext context)
{
return this.ProcessImageAsyncTask(context).ToTask();
}
/// <summary> /// <summary>
/// Processes the image. /// Processes the image.
/// </summary> /// </summary>
@ -158,19 +128,19 @@ namespace ImageProcessor.Web.HttpModules
/// references to the intrinsic server objects /// references to the intrinsic server objects
/// </param> /// </param>
/// <returns> /// <returns>
/// The <see cref="IEnumerable{Task}"/>. /// The <see cref="T:System.Threading.Tasks.Task"/>.
/// </returns> /// </returns>
private IEnumerable<Task> ProcessImageAsyncTask(HttpContext context) private async Task ProcessImageAsync(HttpContext context)
{ {
// Is this a remote file. HttpRequest request = context.Request;
bool isRemote = context.Request.Path.Equals(RemotePrefix, StringComparison.OrdinalIgnoreCase); bool isRemote = request.Path.Equals(RemotePrefix, StringComparison.OrdinalIgnoreCase);
string requestPath = string.Empty; string requestPath = string.Empty;
string queryString = string.Empty; string queryString = string.Empty;
if (isRemote) if (isRemote)
{ {
// We need to split the querystring to get the actual values we want. // We need to split the querystring to get the actual values we want.
string urlDecode = HttpUtility.UrlDecode(context.Request.QueryString.ToString()); string urlDecode = HttpUtility.UrlDecode(request.QueryString.ToString());
if (urlDecode != null) if (urlDecode != null)
{ {
@ -186,129 +156,87 @@ namespace ImageProcessor.Web.HttpModules
} }
else else
{ {
requestPath = HostingEnvironment.MapPath(context.Request.Path); requestPath = HostingEnvironment.MapPath(request.Path);
queryString = HttpUtility.UrlDecode(context.Request.QueryString.ToString()); queryString = HttpUtility.UrlDecode(request.QueryString.ToString());
} }
// Only process requests that pass our sanitizing filter. // Only process requests that pass our sanitizing filter.
if (ImageUtils.IsValidImageExtension(requestPath) && !string.IsNullOrWhiteSpace(queryString)) if (ImageUtils.IsValidImageExtension(requestPath) && !string.IsNullOrWhiteSpace(queryString))
{ {
if (this.FileExists(requestPath, isRemote)) string fullPath = string.Format("{0}?{1}", requestPath, queryString);
{ string imageName = Path.GetFileName(requestPath);
string fullPath = string.Format("{0}?{1}", requestPath, queryString); // Create a new cache to help process and cache the request.
string imageName = Path.GetFileName(requestPath); DiskCache cache = new DiskCache(request, requestPath, fullPath, imageName, isRemote);
// Create a new cache to help process and cache the request. // Is the file new or updated?
Cache cache = new Cache(requestPath, fullPath, imageName, isRemote); bool isNewOrUpdated = await cache.IsNewOrUpdatedFileAsync();
// Is the file new or updated? // Only process if the file has been updated.
Task<bool> isUpdatedTask = cache.isNewOrUpdatedFileAsync(); if (isNewOrUpdated)
yield return isUpdatedTask; {
bool isNewOrUpdated = isUpdatedTask.Result; // Process the image.
using (ImageFactory imageFactory = new ImageFactory())
// Only process if the file has been updated.
if (isNewOrUpdated)
{ {
// Process the image. if (isRemote)
using (ImageFactory imageFactory = new ImageFactory())
{ {
if (isRemote) Uri uri = new Uri(requestPath);
{
Uri uri = new Uri(requestPath);
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
Task<WebResponse> responseTask = webRequest.GetResponseAsync(); RemoteFile remoteFile = new RemoteFile(uri, false);
yield return responseTask;
//RemoteFile remoteFile = new RemoteFile(uri, false);
//Task<WebResponse> getWebResponseTask = remoteFile.GetWebResponseAsync(); // Prevent response blocking.
//yield return getWebResponseTask; WebResponse webResponse = await remoteFile.GetWebResponseAsync().ConfigureAwait(false);
using (MemoryStream memoryStream = new MemoryStream()) using (MemoryStream memoryStream = new MemoryStream())
{
using (WebResponse response = webResponse)
{ {
using (WebResponse response = responseTask.Result) using (Stream responseStream = response.GetResponseStream())
{ {
using (Stream responseStream = response.GetResponseStream()) if (responseStream != null)
{ {
if (responseStream != null) // Trim the cache.
{ await cache.TrimCachedFoldersAsync();
// Trim the cache.
Task trimCachedFoldersTask = cache.TrimCachedFoldersAsync();
yield return trimCachedFoldersTask;
responseStream.CopyTo(memoryStream);
imageFactory.Load(memoryStream)
.AddQueryString(queryString)
.Format(ImageUtils.GetImageFormat(imageName))
.AutoProcess().Save(cache.CachedPath);
// Ensure that the LastWriteTime property of the source and cached file match.
Task<DateTime> setCachedLastWriteTimeTask = cache.SetCachedLastWriteTimeAsync();
yield return setCachedLastWriteTimeTask;
DateTime dateTime = setCachedLastWriteTimeTask.Result;
// Add to the cache.
Task addImageToCacheTask = cache.AddImageToCacheAsync(dateTime);
yield return addImageToCacheTask;
}
}
} responseStream.CopyTo(memoryStream);
}
}
else
{
// Trim the cache.
Task trimCachedFoldersTask = cache.TrimCachedFoldersAsync();
yield return trimCachedFoldersTask;
imageFactory.Load(fullPath).AutoProcess().Save(cache.CachedPath); imageFactory.Load(memoryStream)
.AddQueryString(queryString)
.Format(ImageUtils.GetImageFormat(imageName))
.AutoProcess().Save(cache.CachedPath);
// Ensure that the LastWriteTime property of the source and cached file match. // Ensure that the LastWriteTime property of the source and cached file match.
Task<DateTime> setCachedLastWriteTimeTask = cache.SetCachedLastWriteTimeAsync(); DateTime dateTime = await cache.SetCachedLastWriteTimeAsync();
yield return setCachedLastWriteTimeTask;
DateTime dateTime = setCachedLastWriteTimeTask.Result;
// Add to the cache.
Task addImageToCacheTask = cache.AddImageToCacheAsync(dateTime);
yield return addImageToCacheTask;
// Add to the cache.
await cache.AddImageToCacheAsync(dateTime);
}
}
}
} }
} }
} else
{
// Trim the cache.
await cache.TrimCachedFoldersAsync();
context.Items[CachedResponseTypeKey] = ImageUtils.GetResponseType(imageName).ToDescription(); imageFactory.Load(fullPath).AutoProcess().Save(cache.CachedPath);
// The cached file is valid so just rewrite the path. // Ensure that the LastWriteTime property of the source and cached file match.
context.RewritePath(cache.GetVirtualPath(cache.CachedPath, context.Request), false); DateTime dateTime = await cache.SetCachedLastWriteTimeAsync();
yield break;
// Add to the cache.
await cache.AddImageToCacheAsync(dateTime);
}
}
} }
}
yield break;
}
// Store the response type in the context for later retrieval.
context.Items[CachedResponseTypeKey] = ImageUtils.GetResponseType(imageName).ToDescription();
/// <summary> // The cached file is valid so just rewrite the path.
/// returns a value indicating whether a file exists. context.RewritePath(cache.GetVirtualCachedPath(), false);
/// </summary>
/// <param name="path">The path to the file to check.</param>
/// <param name="isRemote">Whether the file is remote.</param>
/// <returns>True if the file exists, otherwise false.</returns>
/// <remarks>If the file is remote the method will always return true.</remarks>
private bool FileExists(string path, bool isRemote)
{
if (isRemote)
{
return true;
} }
FileInfo fileInfo = new FileInfo(path);
return fileInfo.Exists;
} }
/// <summary> /// <summary>
@ -327,7 +255,7 @@ namespace ImageProcessor.Web.HttpModules
response.ContentType = responseType; response.ContentType = responseType;
response.AddHeader("Image-Served-By", "ImageProcessor/" + AssemblyVersion); response.AddHeader("Image-Served-By", "ImageProcessor.Web/" + AssemblyVersion);
HttpCachePolicy cache = response.Cache; HttpCachePolicy cache = response.Cache;

7
src/ImageProcessor.Web/ImageFactoryExtensions.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ImageFactoryExtensions.cs" company="James South"> // <copyright file="ImageFactoryExtensions.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -38,17 +38,18 @@ namespace ImageProcessor.Web
{ {
if (factory.ShouldProcess) if (factory.ShouldProcess)
{ {
// It's faster to lock and run through our activated list than to create new instances.
lock (SyncRoot) lock (SyncRoot)
{ {
// Get a list of all graphics processors that have parsed and matched the querystring. // Get a list of all graphics processors that have parsed and matched the querystring.
List<IGraphicsProcessor> list = List<IGraphicsProcessor> graphicsProcessors =
ImageProcessorConfig.Instance.GraphicsProcessors ImageProcessorConfig.Instance.GraphicsProcessors
.Where(x => x.MatchRegexIndex(factory.QueryString) != int.MaxValue) .Where(x => x.MatchRegexIndex(factory.QueryString) != int.MaxValue)
.OrderBy(y => y.SortOrder) .OrderBy(y => y.SortOrder)
.ToList(); .ToList();
// Loop through and process the image. // Loop through and process the image.
foreach (IGraphicsProcessor graphicsProcessor in list) foreach (IGraphicsProcessor graphicsProcessor in graphicsProcessors)
{ {
factory.Image = graphicsProcessor.ProcessImage(factory); factory.Image = graphicsProcessor.ProcessImage(factory);
} }

31
src/ImageProcessor.Web/ImageProcessor.Web.csproj

@ -66,6 +66,18 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.14-rc\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.14-rc\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.14.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.14-rc\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@ -78,6 +90,14 @@
<HintPath>..\packages\System.Data.SQLite.x86.1.0.84.0\lib\net40\System.Data.SQLite.Linq.dll</HintPath> <HintPath>..\packages\System.Data.SQLite.x86.1.0.84.0\lib\net40\System.Data.SQLite.Linq.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Net" />
<Reference Include="System.Runtime">
<HintPath>..\packages\Microsoft.Bcl.1.0.16-rc\lib\net40\System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks, Version=2.5.16.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.1.0.16-rc\lib\net40\System.Threading.Tasks.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="System.Web" /> <Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
@ -87,10 +107,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Caching\CachedImage.cs" /> <Compile Include="Caching\CachedImage.cs" />
<Compile Include="Caching\Cache.cs" />
<Compile Include="Caching\DiskCache.cs" /> <Compile Include="Caching\DiskCache.cs" />
<Compile Include="Helpers\AsyncIoExtensions.cs" /> <Compile Include="Helpers\TaskHelpers.cs" />
<Compile Include="Helpers\TaskEx.cs" />
<Compile Include="Helpers\LockedDictionary.cs" /> <Compile Include="Helpers\LockedDictionary.cs" />
<Compile Include="Caching\PersistantDictionary.cs" /> <Compile Include="Caching\PersistantDictionary.cs" />
<Compile Include="Caching\SQLContext.cs" /> <Compile Include="Caching\SQLContext.cs" />
@ -110,9 +128,16 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.0-rc\tools\Microsoft.Bcl.Build.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy /y "$(TargetPath)" "$(SolutionDir)\Test\Test\bin"
xcopy /y "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)\Test\Test\bin"</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">

4
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 // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly: AssemblyVersion("2.0.1.0")] [assembly: AssemblyVersion("2.1.0.0")]
[assembly: AssemblyFileVersion("2.0.1.0")] [assembly: AssemblyFileVersion("2.1.0.0")]

15
src/ImageProcessor.Web/app.config

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns:bcl="urn:schemas-microsoft-com:bcl" xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly bcl:name="System.Runtime">
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
<dependentAssembly bcl:name="System.Threading.Tasks">
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

3
src/ImageProcessor.Web/packages.config

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Microsoft.Bcl" version="1.0.16-rc" targetFramework="net40" />
<package id="Microsoft.Bcl.Async" version="1.0.14-rc" targetFramework="net40" />
<package id="Microsoft.Bcl.Build" version="1.0.0-rc" targetFramework="net40" />
<package id="System.Data.SQLite.x86" version="1.0.84.0" targetFramework="net40" /> <package id="System.Data.SQLite.x86" version="1.0.84.0" targetFramework="net40" />
</packages> </packages>

2
src/ImageProcessor/Helpers/Extensions/EnumExtensions.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="EnumExtensions.cs" company="James South"> // <copyright file="EnumExtensions.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Helpers/Extensions/StringExtensions.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="StringExtensions.cs" company="James South"> // <copyright file="StringExtensions.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/ImageFactory.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ImageFactory.cs" company="James South"> // <copyright file="ImageFactory.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/BlackWhiteMatrixFilter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="BlackWhiteMatrixFilter.cs" company="James South"> // <copyright file="BlackWhiteMatrixFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/ColorMatrixes.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ColorMatrixes.cs" company="James South"> // <copyright file="ColorMatrixes.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ComicMatrixFilter.cs" company="James South"> // <copyright file="ComicMatrixFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/GothamMatrixFilter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="GothamMatrixFilter.cs" company="James South"> // <copyright file="GothamMatrixFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/GreyScaleMatrixFilter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="GreyScaleMatrixFilter.cs" company="James South"> // <copyright file="GreyScaleMatrixFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/HiSatchMatrixFilter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="HiSatchMatrixFilter.cs" company="James South"> // <copyright file="HiSatchMatrixFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/IMatrixFilter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="IMatrixFilter.cs" company="James South"> // <copyright file="IMatrixFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/InvertMatrixFilter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="InvertMatrixFilter.cs" company="James South"> // <copyright file="InvertMatrixFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/LoSatchMatrixFilter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="LoSatchMatrixFilter.cs" company="James South"> // <copyright file="LoSatchMatrixFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="LomographMatrixFilter.cs" company="James South"> // <copyright file="LomographMatrixFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/PolaroidMatrixFilter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="PolaroidMatrixFilter.cs" company="James South"> // <copyright file="PolaroidMatrixFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Filters/SepiaMatrixFilter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="SepiaMatrixFilter.cs" company="James South"> // <copyright file="SepiaMatrixFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/ImageUtils.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ImageUtils.cs" company="James South"> // <copyright file="ImageUtils.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/OctreeQuantizer.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="OctreeQuantizer.cs" company="James South"> // <copyright file="OctreeQuantizer.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/Quantizer.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="Quantizer.cs" company="James South"> // <copyright file="Quantizer.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/ResponseType.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ResponseType.cs" company="James South"> // <copyright file="ResponseType.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/RotateLayer.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="RotateLayer.cs" company="James South"> // <copyright file="RotateLayer.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Imaging/TextLayer.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="TextLayer.cs" company="James South"> // <copyright file="TextLayer.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Processors/Alpha.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="Alpha.cs" company="James South"> // <copyright file="Alpha.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

4
src/ImageProcessor/Processors/Crop.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="Crop.cs" company="James South"> // <copyright file="Crop.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -46,7 +46,7 @@ namespace ImageProcessor.Processors
{ {
get get
{ {
return "Crops an image to the given directions."; return "Crops an image to the given dimensions.";
} }
} }

2
src/ImageProcessor/Processors/Filter.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="Filter.cs" company="James South"> // <copyright file="Filter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Processors/Flip.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="Flip.cs" company="James South"> // <copyright file="Flip.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Processors/Format.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="Format.cs" company="James South"> // <copyright file="Format.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Processors/IGraphicsProcessor.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="IGraphicsProcessor.cs" company="James South"> // <copyright file="IGraphicsProcessor.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Processors/Quality.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="Quality.cs" company="James South"> // <copyright file="Quality.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Processors/Resize.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="Resize.cs" company="James South"> // <copyright file="Resize.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Processors/Rotate.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="Rotate.cs" company="James South"> // <copyright file="Rotate.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Processors/Vignette.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="Vignette.cs" company="James South"> // <copyright file="Vignette.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

2
src/ImageProcessor/Processors/Watermark.cs

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="Watermark.cs" company="James South"> // <copyright file="Watermark.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Dual licensed under the MIT or GPL Version 2 licenses. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

4
src/ImageProcessor/Properties/AssemblyInfo.cs

@ -32,6 +32,6 @@ using System.Security;
// //
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly: AssemblyVersion("1.4.0.0")] [assembly: AssemblyVersion("1.4.1.0")]
[assembly: AssemblyFileVersion("1.4.0.0")] [assembly: AssemblyFileVersion("1.4.1.0")]

25
src/Test/Test/Controllers/HomeController.cs

@ -11,7 +11,7 @@ namespace Test.Controllers
using System.Web.Hosting; using System.Web.Hosting;
using ImageProcessor.Helpers.Extensions; using ImageProcessor.Helpers.Extensions;
using ImageProcessor.Web.Caching; //using ImageProcessor.Web.Caching;
public class HomeController : Controller public class HomeController : Controller
{ {
@ -55,13 +55,13 @@ namespace Test.Controllers
return this.View(); return this.View();
} }
public ActionResult Speed() public ActionResult Collisions()
{ {
DateTime start = DateTime.Now; DateTime start = DateTime.Now;
List<double> collisions = new List<double>(); List<double> collisions = new List<double>();
const int Iterations = 1; const int Iterations = 1;
const int Maxitems = 360000; const int Maxitems = 3600000;
for (int i = 0; i < Iterations; i++) for (int i = 0; i < Iterations; i++)
{ {
@ -71,7 +71,7 @@ namespace Test.Controllers
{ {
string path = Path.GetRandomFileName().ToMD5Fingerprint(); string path = Path.GetRandomFileName().ToMD5Fingerprint();
path = string.Format("{0}{1}", path.Substring(0, 4), path.Substring(16, 4)); path = string.Format("/{0}/{1}/{2}", path.Substring(0, 1), path.Substring(31, 1), path.Substring(0, 8));
paths.Add(path); paths.Add(path);
} }
@ -84,26 +84,9 @@ namespace Test.Controllers
double averageCollisionRate = collisions.Average(); double averageCollisionRate = collisions.Average();
//PersistantDictionary persistantDictionary = PersistantDictionary.Instance;
//for (int i = 0; i < 1000; i++)
//{
// string random = Path.GetRandomFileName();
// random = random + random;
// CachedImage cachedImage = new CachedImage(random, DateTime.UtcNow, DateTime.UtcNow);
// persistantDictionary.GetOrAdd(random, x => cachedImage);
//}
//KeyValuePair<string, CachedImage> pair = persistantDictionary.First();
//CachedImage image;
//persistantDictionary.TryRemove(pair.Key, out image);
TimeSpan timeSpan = DateTime.Now - start; TimeSpan timeSpan = DateTime.Now - start;
//ViewBag.Count = count;
ViewBag.Collision = averageCollisionRate; ViewBag.Collision = averageCollisionRate;
return this.View(timeSpan); return this.View(timeSpan);

2
src/Test/Test/Images/Thumbs.db.REMOVED.git-id

@ -1 +1 @@
8f290942360078af430fc9ce5d6e746500d21d74 df51932368e72ec3c9b9897d29e27dcf20af7395

0
src/Test/Test/Images/6287131503_9b1f82e4f0_b.jpg.REMOVED.git-id → src/Test/Test/Images/udendørs.jpg.REMOVED.git-id

4
src/Test/Test/Test.csproj

@ -122,7 +122,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\ImageProcessor.Web\ImageProcessor.Web.csproj"> <ProjectReference Include="..\..\ImageProcessor.Web\ImageProcessor.Web.csproj">
<Project>{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}</Project> <Project>{4f7050f2-465f-4e10-8db2-2fb97ac6aa43}</Project>
<Name>ImageProcessor.Web</Name> <Name>ImageProcessor.Web</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\ImageProcessor\ImageProcessor.csproj"> <ProjectReference Include="..\..\ImageProcessor\ImageProcessor.csproj">
@ -134,7 +134,7 @@
<Content Include="Views\Home\Responsive.cshtml" /> <Content Include="Views\Home\Responsive.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Views\Home\Speed.cshtml" /> <Content Include="Views\Home\Collisions.cshtml" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>

1
src/Test/Test/Views/Home/Speed.cshtml → src/Test/Test/Views/Home/Collisions.cshtml

@ -14,7 +14,6 @@
<body> <body>
<div> <div>
Speed In Milliseconds: @s<br/> Speed In Milliseconds: @s<br/>
@* Distinct Count: @ViewBag.Count*@
Collision Rate: @ViewBag.Collision% Collision Rate: @ViewBag.Collision%
</div> </div>
</body> </body>

2
src/Test/Test/Views/Home/Index.cshtml

@ -8,6 +8,8 @@
<div class="clmn2"> <div class="clmn2">
<h2>Resized</h2> <h2>Resized</h2>
<img src="/images/Penguins.jpg?width=300" /> <img src="/images/Penguins.jpg?width=300" />
<h3>Foreign language test.</h3>
<img src="/images/udendørs.jpg?width=300" />
</div> </div>
<div class="clmn2"> <div class="clmn2">
<h2>Cropped </h2> <h2>Cropped </h2>

64
src/Test/Test/Web.config

@ -1,4 +1,4 @@
<?xml version="1.0"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
For more information on how to configure your ASP.NET application, please visit For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=152368 http://go.microsoft.com/fwlink/?LinkId=152368
@ -7,70 +7,78 @@
<!-- Configuration section-handler declaration area. --> <!-- Configuration section-handler declaration area. -->
<configSections> <configSections>
<sectionGroup name="imageProcessor"> <sectionGroup name="imageProcessor">
<section name="security" requirePermission="false" type="ImageProcessor.Web.Config.ImageSecuritySection, ImageProcessor.Web"/> <section name="security" requirePermission="false" type="ImageProcessor.Web.Config.ImageSecuritySection, ImageProcessor.Web" />
<section name="processing" requirePermission="false" type="ImageProcessor.Web.Config.ImageProcessingSection, ImageProcessor.Web"/> <section name="processing" requirePermission="false" type="ImageProcessor.Web.Config.ImageProcessingSection, ImageProcessor.Web" />
<section name="cache" requirePermission="false" type="ImageProcessor.Web.Config.ImageCacheSection, ImageProcessor.Web"/> <section name="cache" requirePermission="false" type="ImageProcessor.Web.Config.ImageCacheSection, ImageProcessor.Web" />
</sectionGroup> </sectionGroup>
</configSections> </configSections>
<appSettings> <appSettings>
<add key="webpages:Version" value="1.0.0.0"/> <add key="webpages:Version" value="1.0.0.0" />
<add key="ClientValidationEnabled" value="true"/> <add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true"/> <add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings> </appSettings>
<system.web> <system.web>
<compilation debug="true" targetFramework="4.0"> <compilation debug="true" targetFramework="4.0">
<assemblies> <assemblies>
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies> </assemblies>
</compilation> </compilation>
<authentication mode="Forms"> <authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880"/> <forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication> </authentication>
<pages> <pages>
<namespaces> <namespaces>
<add namespace="System.Web.Helpers"/> <add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc"/> <add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax"/> <add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html"/> <add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing"/> <add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages"/> <add namespace="System.Web.WebPages" />
</namespaces> </namespaces>
</pages> </pages>
<httpModules> <httpModules>
<add name="ImageProcessorModule" type="ImageProcessor.Web.HttpModules.ImageProcessingModule, ImageProcessor.Web"/> <add name="ImageProcessorModule" type="ImageProcessor.Web.HttpModules.ImageProcessingModule, ImageProcessor.Web" />
</httpModules> </httpModules>
<!--Set the trust level.--> <!--Set the trust level.-->
<!--<trust level="Medium"/>--> <!--<trust level="Medium"/>-->
</system.web> </system.web>
<system.webServer> <system.webServer>
<validation validateIntegratedModeConfiguration="false"/> <validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true"/> <modules runAllManagedModulesForAllRequests="true" />
</system.webServer> </system.webServer>
<runtime> <runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/> <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0"/> <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly> </dependentAssembly>
</assemblyBinding> </assemblyBinding>
</runtime> </runtime>
<imageProcessor> <imageProcessor>
<security allowRemoteDownloads="true" timeout="300000" maxBytes="524288" remotePrefix="/remote.axd"> <security allowRemoteDownloads="true" timeout="300000" maxBytes="524288" remotePrefix="/remote.axd">
<whiteList> <whiteList>
<add url="http://images.mymovies.net"/> <add url="http://images.mymovies.net" />
</whiteList> </whiteList>
</security> </security>
<cache virtualPath="~/cache" maxDays="56"/> <cache virtualPath="~/cache" maxDays="56" />
<processing> <processing>
<plugins> <plugins>
<plugin name="Resize"> <plugin name="Resize">
<settings> <settings>
<setting key="MaxWidth" value="1024"/> <setting key="MaxWidth" value="1024" />
<setting key="MaxHeight" value="768"/> <setting key="MaxHeight" value="768" />
</settings> </settings>
</plugin> </plugin>
</plugins> </plugins>

1
src/packages/Microsoft.Bcl.1.0.16-rc/License.rtf.REMOVED.git-id

@ -0,0 +1 @@
30ff7aa1ad2a7eedde4972dee464f229d4459439

1
src/packages/Microsoft.Bcl.1.0.16-rc/Microsoft.Bcl.1.0.16-rc.nupkg.REMOVED.git-id

@ -0,0 +1 @@
168ac0ce88f1c4eeb97a4ad4665e4f0f3bfc4fd6

44
src/packages/Microsoft.Bcl.1.0.16-rc/Microsoft.Bcl.1.0.16-rc.nuspec

@ -0,0 +1,44 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Microsoft.Bcl</id>
<version>1.0.16-rc</version>
<title>BCL Portability Pack for .NET Framework 4, Silverlight 4 and 5, and Windows Phone 7.5</title>
<authors>Microsoft</authors>
<owners>Microsoft</owners>
<licenseUrl>http://go.microsoft.com/fwlink/?LinkID=261998&amp;clcid=0x409</licenseUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>This packages enables projects targeting .NET Framework 4, Silverlight 4 and 5, and Windows Phone 7.5 (including any portable library combinations) to use new types from later versions of .NET including:
CallerMemberNameAttribute
CallerLineNumberAttribute
CallerFilePathAttribute
Tuple&lt;T1, T2, ...&gt;
IProgress&lt;T&gt;
IStructuralComparable
IStructuralEquatable
Task
These types are "unified" to their later version equivalent. For example, when running on .NET Framework 4.5, IProgress&lt;T&gt; from this package will be seen by the runtime as the same type as the one already in the platform.
This package is not required for projects targeting .NET Framework 4.5 or .NET for Windows Store apps. For known issues, please see: http://blogs.msdn.com/b/bclteam/p/asynctargetingpackkb.aspx.</description>
<summary>Adds support for types from later versions to .NET Framework 4, Silverlight 4 and 5, and Windows Phone 7.5.</summary>
<copyright>Copyright © Microsoft Corporation</copyright>
<tags>BCL Microsoft System Task IProgress</tags>
<dependencies>
<group>
<dependency id="Microsoft.Bcl.Build" version="1.0.0-rc" />
</group>
<group targetFramework="Silverlight4.0" />
<group targetFramework=".NETFramework4.5" />
<group targetFramework="Windows8.0" />
<group targetFramework="WindowsPhone8.0" />
<group targetFramework=".NETPortable0.0-net45+win80+wp80" />
</dependencies>
<references>
<reference file="System.Runtime.dll" />
<reference file="System.Threading.Tasks.dll" />
<reference file="_._" />
</references>
</metadata>
</package>

24
src/packages/Microsoft.Bcl.1.0.16-rc/ReleaseNotes.txt

@ -0,0 +1,24 @@
Changes in 1.0.16-rc
- Fixed: Adding empty content to .NET 4.5, Windows Phone 8, Windows 8 and portable combinations, so that app.config transforms
are not applied to projects targeting them.
Changes in 1.0.15-rc
- Fixed: System.Runtime is missing a type forward for Tuple<T1, T2>
Changes in 1.0.14-rc
- Fixed: System.Runtime now has a fixed version for Phone 7.x due to the lack of a way to redirect them to a later version.
Changes in 1.0.13-rc
- Fixed: First-chance exceptions when running on Phone 7.x
Changes in 1.0.12-rc
- Fixed: Microsoft.Bcl.targets are not imported when using NuGet 2.0 to install Microsoft.Bcl
- Changed: Pulled build targets into a separate package (Microsoft.Bcl.Build) so other BCL packages can depend on it.
Changes in 1.0.11-beta
- Initial release

15
src/packages/Microsoft.Bcl.1.0.16-rc/content/net40/app.config.transform

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns:bcl="urn:schemas-microsoft-com:bcl" xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly bcl:name="System.Runtime">
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
<dependentAssembly bcl:name="System.Threading.Tasks">
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

15
src/packages/Microsoft.Bcl.1.0.16-rc/content/net40/web.config.transform

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns:bcl="urn:schemas-microsoft-com:bcl" xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly bcl:name="System.Runtime">
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
<dependentAssembly bcl:name="System.Threading.Tasks">
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

0
src/packages/Microsoft.Bcl.1.0.16-rc/content/net45/_._

15
src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+sl4+win8+wp71/app.config.transform

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns:bcl="urn:schemas-microsoft-com:bcl" xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly bcl:name="System.Runtime">
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.5.11.0" newVersion="1.5.11.0" />
</dependentAssembly>
<dependentAssembly bcl:name="System.Threading.Tasks">
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.5.11.0" newVersion="1.5.11.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

15
src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+sl4+win8+wp8/app.config.transform

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns:bcl="urn:schemas-microsoft-com:bcl" xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly bcl:name="System.Runtime">
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
<dependentAssembly bcl:name="System.Threading.Tasks">
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.5.11.0" newVersion="1.5.11.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

15
src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+sl4+win8/app.config.transform

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns:bcl="urn:schemas-microsoft-com:bcl" xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly bcl:name="System.Runtime">
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
<dependentAssembly bcl:name="System.Threading.Tasks">
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.5.11.0" newVersion="1.5.11.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

15
src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+sl5+win8+wp8/app.config.transform

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns:bcl="urn:schemas-microsoft-com:bcl" xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly bcl:name="System.Runtime">
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
<dependentAssembly bcl:name="System.Threading.Tasks">
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

15
src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+win8+wp8/app.config.transform

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns:bcl="urn:schemas-microsoft-com:bcl" xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly bcl:name="System.Runtime">
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
<dependentAssembly bcl:name="System.Threading.Tasks">
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

15
src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net40+win8/app.config.transform

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns:bcl="urn:schemas-microsoft-com:bcl" xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly bcl:name="System.Runtime">
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
<dependentAssembly bcl:name="System.Threading.Tasks">
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.16.0" newVersion="2.5.16.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

0
src/packages/Microsoft.Bcl.1.0.16-rc/content/portable-net45+win8+wp8/_._

15
src/packages/Microsoft.Bcl.1.0.16-rc/content/sl4-windowsphone71/app.config.transform

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns:bcl="urn:schemas-microsoft-com:bcl" xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly bcl:name="System.Runtime">
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.5.11.0" newVersion="1.5.11.0" />
</dependentAssembly>
<dependentAssembly bcl:name="System.Threading.Tasks">
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.5.11.0" newVersion="1.5.11.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

0
src/packages/Microsoft.Bcl.1.0.16-rc/content/sl4/_._

0
src/packages/Microsoft.Bcl.1.0.16-rc/content/sl5/_._

0
src/packages/Microsoft.Bcl.1.0.16-rc/content/win8/_._

0
src/packages/Microsoft.Bcl.1.0.16-rc/content/wp8/_._

BIN
src/packages/Microsoft.Bcl.1.0.16-rc/lib/net40/System.Runtime.dll

Binary file not shown.

56
src/packages/Microsoft.Bcl.1.0.16-rc/lib/net40/System.Runtime.xml

@ -0,0 +1,56 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>System.Runtime</name>
</assembly>
<members>
<member name="T:System.IProgress`1">
<summary>Defines a provider for progress updates.</summary>
<typeparam name="T">The type of progress update value.</typeparam>
</member>
<member name="M:System.IProgress`1.Report(`0)">
<summary>Reports a progress update.</summary>
<param name="value">The value of the updated progress.</param>
</member>
<member name="T:System.Runtime.CompilerServices.AsyncStateMachineAttribute">
<summary>Identities the async state machine type for this method.</summary>
</member>
<member name="T:System.Runtime.CompilerServices.StateMachineAttribute">
<summary>Identities the state machine type for this method.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.StateMachineAttribute.#ctor(System.Type)">
<summary>Initializes the attribute.</summary>
<param name="stateMachineType">The type that implements the state machine.</param>
</member>
<member name="P:System.Runtime.CompilerServices.StateMachineAttribute.StateMachineType">
<summary>Gets the type that implements the state machine.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncStateMachineAttribute.#ctor(System.Type)">
<summary>Initializes the attribute.</summary>
<param name="stateMachineType">The type that implements the state machine.</param>
</member>
<member name="T:System.Runtime.CompilerServices.CallerMemberNameAttribute">
<summary>
Allows you to obtain the method or property name of the caller to the method.
</summary>
</member>
<member name="T:System.Runtime.CompilerServices.CallerLineNumberAttribute">
<summary>
Allows you to obtain the line number in the source file at which the method is called.
</summary>
</member>
<member name="T:System.Runtime.CompilerServices.CallerFilePathAttribute">
<summary>
Allows you to obtain the full path of the source file that contains the caller.
This is the file path at the time of compile.
</summary>
</member>
<member name="T:System.Runtime.CompilerServices.IteratorStateMachineAttribute">
<summary>Identities the iterator state machine type for this method.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.IteratorStateMachineAttribute.#ctor(System.Type)">
<summary>Initializes the attribute.</summary>
<param name="stateMachineType">The type that implements the state machine.</param>
</member>
</members>
</doc>

BIN
src/packages/Microsoft.Bcl.1.0.16-rc/lib/net40/System.Threading.Tasks.dll

Binary file not shown.

475
src/packages/Microsoft.Bcl.1.0.16-rc/lib/net40/System.Threading.Tasks.xml

@ -0,0 +1,475 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>System.Threading.Tasks</name>
</assembly>
<members>
<member name="T:System.Runtime.CompilerServices.AsyncMethodBuilderCore">
<summary>Holds state related to the builder's IAsyncStateMachine.</summary>
<remarks>This is a mutable struct. Be very delicate with it.</remarks>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncMethodBuilderCore.m_stateMachine">
<summary>A reference to the heap-allocated state machine object associated with this builder.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start``1(``0@)">
<summary>Initiates the builder's execution with the associated state machine.</summary>
<typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
<param name="stateMachine">The state machine instance, passed by reference.</param>
<exception cref="T:System.ArgumentNullException">The <paramref name="stateMachine"/> argument is null (Nothing in Visual Basic).</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodBuilderCore.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)">
<summary>Associates the builder with the state machine it represents.</summary>
<param name="stateMachine">The heap-allocated state machine object.</param>
<exception cref="T:System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
<exception cref="T:System.InvalidOperationException">The builder is incorrectly initialized.</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodBuilderCore.GetCompletionAction``2(``0@,``1@)">
<summary>
Gets the Action to use with an awaiter's OnCompleted or UnsafeOnCompleted method.
On first invocation, the supplied state machine will be boxed.
</summary>
<typeparam name="TMethodBuilder">Specifies the type of the method builder used.</typeparam>
<typeparam name="TStateMachine">Specifies the type of the state machine used.</typeparam>
<param name="builder">The builder.</param>
<param name="stateMachine">The state machine.</param>
<returns>An Action to provide to the awaiter.</returns>
</member>
<member name="T:System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner">
<summary>Provides the ability to invoke a state machine's MoveNext method under a supplied ExecutionContext.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.m_context">
<summary>The context with which to run MoveNext.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.m_stateMachine">
<summary>The state machine whose MoveNext method should be invoked.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.#ctor(System.ExecutionContextLightup)">
<summary>Initializes the runner.</summary>
<param name="context">The context with which to run MoveNext.</param>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run">
<summary>Invokes MoveNext under the provided context.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.s_invokeMoveNext">
<summary>Cached delegate used with ExecutionContext.Run.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(System.Object)">
<summary>Invokes the MoveNext method on the supplied IAsyncStateMachine.</summary>
<param name="stateMachine">The IAsyncStateMachine machine instance.</param>
</member>
<member name="T:System.Runtime.CompilerServices.AsyncMethodTaskCache`1">
<summary>Provides a base class used to cache tasks of a specific return type.</summary>
<typeparam name="TResult">Specifies the type of results the cached tasks return.</typeparam>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.Singleton">
<summary>
A singleton cache for this result type.
This may be null if there are no cached tasks for this TResult.
</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.CreateCompleted(`0)">
<summary>Creates a non-disposable task.</summary>
<param name="result">The result for the task.</param>
<returns>The cacheable task.</returns>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.CreateCache">
<summary>Creates a cache.</summary>
<returns>A task cache for this result type.</returns>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.FromResult(`0)">
<summary>Gets a cached task if one exists.</summary>
<param name="result">The result for which we want a cached task.</param>
<returns>A cached task if one exists; otherwise, null.</returns>
</member>
<member name="T:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.AsyncMethodBooleanTaskCache">
<summary>Provides a cache for Boolean tasks.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.AsyncMethodBooleanTaskCache.m_true">
<summary>A true task.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.AsyncMethodBooleanTaskCache.m_false">
<summary>A false task.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.AsyncMethodBooleanTaskCache.FromResult(System.Boolean)">
<summary>Gets a cached task for the Boolean result.</summary>
<param name="result">true or false</param>
<returns>A cached task for the Boolean result.</returns>
</member>
<member name="T:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.AsyncMethodInt32TaskCache">
<summary>Provides a cache for zero Int32 tasks.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.AsyncMethodInt32TaskCache.INCLUSIVE_INT32_MIN">
<summary>The minimum value, inclusive, for which we want a cached task.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.AsyncMethodInt32TaskCache.EXCLUSIVE_INT32_MAX">
<summary>The maximum value, exclusive, for which we want a cached task.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.AsyncMethodInt32TaskCache.Int32Tasks">
<summary>The cache of Task{Int32}.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.AsyncMethodInt32TaskCache.CreateInt32Tasks">
<summary>Creates an array of cached tasks for the values in the range [INCLUSIVE_MIN,EXCLUSIVE_MAX).</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncMethodTaskCache`1.AsyncMethodInt32TaskCache.FromResult(System.Int32)">
<summary>Gets a cached task for the zero Int32 result.</summary>
<param name="result">The integer value</param>
<returns>A cached task for the Int32 result or null if not cached.</returns>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncServices.ThrowAsync(System.Exception,System.Threading.SynchronizationContext)">
<summary>Throws the exception on the ThreadPool.</summary>
<param name="exception">The exception to propagate.</param>
<param name="targetContext">The target context on which to propagate the exception. Null to use the ThreadPool.</param>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncServices.PrepareExceptionForRethrow(System.Exception)">
<summary>Copies the exception's stack trace so its stack trace isn't overwritten.</summary>
<param name="exc">The exception to prepare.</param>
</member>
<member name="T:System.Runtime.CompilerServices.AsyncTaskMethodBuilder">
<summary>
Provides a builder for asynchronous methods that return <see cref="T:System.Threading.Tasks.Task"/>.
This type is intended for compiler use only.
</summary>
<remarks>
AsyncTaskMethodBuilder is a value type, and thus it is copied by value.
Prior to being copied, one of its Task, SetResult, or SetException members must be accessed,
or else the copies may end up building distinct Task instances.
</remarks>
</member>
<member name="T:System.Runtime.CompilerServices.IAsyncMethodBuilder">
<summary>Represents an asynchronous method builder.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.s_cachedCompleted">
<summary>A cached VoidTaskResult task used for builders that complete synchronously.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.m_builder">
<summary>The generic builder object to which this non-generic instance delegates.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Create">
<summary>Initializes a new <see cref="T:System.Runtime.CompilerServices.AsyncTaskMethodBuilder"/>.</summary>
<returns>The initialized <see cref="T:System.Runtime.CompilerServices.AsyncTaskMethodBuilder"/>.</returns>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start``1(``0@)">
<summary>Initiates the builder's execution with the associated state machine.</summary>
<typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
<param name="stateMachine">The state machine instance, passed by reference.</param>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)">
<summary>Associates the builder with the state machine it represents.</summary>
<param name="stateMachine">The heap-allocated state machine object.</param>
<exception cref="T:System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
<exception cref="T:System.InvalidOperationException">The builder is incorrectly initialized.</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.System#Runtime#CompilerServices#IAsyncMethodBuilder#PreBoxInitialization">
<summary>Perform any initialization necessary prior to lifting the builder to the heap.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitOnCompleted``2(``0@,``1@)">
<summary>
Schedules the specified state machine to be pushed forward when the specified awaiter completes.
</summary>
<typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
<typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
<param name="awaiter">The awaiter.</param>
<param name="stateMachine">The state machine.</param>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted``2(``0@,``1@)">
<summary>
Schedules the specified state machine to be pushed forward when the specified awaiter completes.
</summary>
<typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
<typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
<param name="awaiter">The awaiter.</param>
<param name="stateMachine">The state machine.</param>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult">
<summary>
Completes the <see cref="T:System.Threading.Tasks.Task"/> in the
<see cref="T:System.Threading.Tasks.TaskStatus">RanToCompletion</see> state.
</summary>
<exception cref="T:System.InvalidOperationException">The builder is not initialized.</exception>
<exception cref="T:System.InvalidOperationException">The task has already completed.</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)">
<summary>
Completes the <see cref="T:System.Threading.Tasks.Task"/> in the
<see cref="T:System.Threading.Tasks.TaskStatus">Faulted</see> state with the specified exception.
</summary>
<param name="exception">The <see cref="T:System.Exception"/> to use to fault the task.</param>
<exception cref="T:System.ArgumentNullException">The <paramref name="exception"/> argument is null (Nothing in Visual Basic).</exception>
<exception cref="T:System.InvalidOperationException">The builder is not initialized.</exception>
<exception cref="T:System.InvalidOperationException">The task has already completed.</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetNotificationForWaitCompletion(System.Boolean)">
<summary>
Called by the debugger to request notification when the first wait operation
(await, Wait, Result, etc.) on this builder's task completes.
</summary>
<param name="enabled">
true to enable notification; false to disable a previously set notification.
</param>
</member>
<member name="P:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Task">
<summary>Gets the <see cref="T:System.Threading.Tasks.Task"/> for this builder.</summary>
<returns>The <see cref="T:System.Threading.Tasks.Task"/> representing the builder's asynchronous operation.</returns>
<exception cref="T:System.InvalidOperationException">The builder is not initialized.</exception>
</member>
<member name="P:System.Runtime.CompilerServices.AsyncTaskMethodBuilder.ObjectIdForDebugger">
<summary>
Gets an object that may be used to uniquely identify this builder to the debugger.
</summary>
<remarks>
This property lazily instantiates the ID in a non-thread-safe manner.
It must only be used by the debugger, and only in a single-threaded manner
when no other threads are in the middle of accessing this property or this.Task.
</remarks>
</member>
<member name="T:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1">
<summary>
Provides a builder for asynchronous methods that return <see cref="T:System.Threading.Tasks.Task`1"/>.
This type is intended for compiler use only.
</summary>
<remarks>
AsyncTaskMethodBuilder{TResult} is a value type, and thus it is copied by value.
Prior to being copied, one of its Task, SetResult, or SetException members must be accessed,
or else the copies may end up building distinct Task instances.
</remarks>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.s_defaultResultTask">
<summary>A cached task for default(TResult).</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.m_coreState">
<summary>State related to the IAsyncStateMachine.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.m_task">
<summary>The lazily-initialized task.</summary>
<remarks>Must be named m_task for debugger step-over to work correctly.</remarks>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.m_taskCompletionSource">
<summary>The lazily-initialized task completion source.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.#cctor">
<summary>Temporary support for disabling crashing if tasks go unobserved.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Create">
<summary>Initializes a new <see cref="T:System.Runtime.CompilerServices.AsyncTaskMethodBuilder"/>.</summary>
<returns>The initialized <see cref="T:System.Runtime.CompilerServices.AsyncTaskMethodBuilder"/>.</returns>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start``1(``0@)">
<summary>Initiates the builder's execution with the associated state machine.</summary>
<typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
<param name="stateMachine">The state machine instance, passed by reference.</param>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)">
<summary>Associates the builder with the state machine it represents.</summary>
<param name="stateMachine">The heap-allocated state machine object.</param>
<exception cref="T:System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
<exception cref="T:System.InvalidOperationException">The builder is incorrectly initialized.</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.System#Runtime#CompilerServices#IAsyncMethodBuilder#PreBoxInitialization">
<summary>Perform any initialization necessary prior to lifting the builder to the heap.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AwaitOnCompleted``2(``0@,``1@)">
<summary>
Schedules the specified state machine to be pushed forward when the specified awaiter completes.
</summary>
<typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
<typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
<param name="awaiter">The awaiter.</param>
<param name="stateMachine">The state machine.</param>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AwaitUnsafeOnCompleted``2(``0@,``1@)">
<summary>
Schedules the specified state machine to be pushed forward when the specified awaiter completes.
</summary>
<typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
<typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
<param name="awaiter">The awaiter.</param>
<param name="stateMachine">The state machine.</param>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetResult(`0)">
<summary>
Completes the <see cref="T:System.Threading.Tasks.Task`1"/> in the
<see cref="T:System.Threading.Tasks.TaskStatus">RanToCompletion</see> state with the specified result.
</summary>
<param name="result">The result to use to complete the task.</param>
<exception cref="T:System.InvalidOperationException">The task has already completed.</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetResult(System.Threading.Tasks.TaskCompletionSource{`0})">
<summary>
Completes the builder by using either the supplied completed task, or by completing
the builder's previously accessed task using default(TResult).
</summary>
<param name="completedTask">A task already completed with the value default(TResult).</param>
<exception cref="T:System.InvalidOperationException">The task has already completed.</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetException(System.Exception)">
<summary>
Completes the <see cref="T:System.Threading.Tasks.Task`1"/> in the
<see cref="T:System.Threading.Tasks.TaskStatus">Faulted</see> state with the specified exception.
</summary>
<param name="exception">The <see cref="T:System.Exception"/> to use to fault the task.</param>
<exception cref="T:System.ArgumentNullException">The <paramref name="exception"/> argument is null (Nothing in Visual Basic).</exception>
<exception cref="T:System.InvalidOperationException">The task has already completed.</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetNotificationForWaitCompletion(System.Boolean)">
<summary>
Called by the debugger to request notification when the first wait operation
(await, Wait, Result, etc.) on this builder's task completes.
</summary>
<param name="enabled">
true to enable notification; false to disable a previously set notification.
</param>
<remarks>
This should only be invoked from within an asynchronous method,
and only by the debugger.
</remarks>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.GetTaskForResult(`0)">
<summary>
Gets a task for the specified result. This will either
be a cached or new task, never null.
</summary>
<param name="result">The result for which we need a task.</param>
<returns>The completed task containing the result.</returns>
</member>
<member name="P:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.CompletionSource">
<summary>Gets the lazily-initialized TaskCompletionSource.</summary>
</member>
<member name="P:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Task">
<summary>Gets the <see cref="T:System.Threading.Tasks.Task`1"/> for this builder.</summary>
<returns>The <see cref="T:System.Threading.Tasks.Task`1"/> representing the builder's asynchronous operation.</returns>
</member>
<member name="P:System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.ObjectIdForDebugger">
<summary>
Gets an object that may be used to uniquely identify this builder to the debugger.
</summary>
<remarks>
This property lazily instantiates the ID in a non-thread-safe manner.
It must only be used by the debugger, and only in a single-threaded manner
when no other threads are in the middle of accessing this property or this.Task.
</remarks>
</member>
<member name="T:System.Runtime.CompilerServices.AsyncVoidMethodBuilder">
<summary>
Provides a builder for asynchronous methods that return void.
This type is intended for compiler use only.
</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.m_synchronizationContext">
<summary>The synchronization context associated with this operation.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.m_coreState">
<summary>State related to the IAsyncStateMachine.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.m_objectIdForDebugger">
<summary>An object used by the debugger to uniquely identify this builder. Lazily initialized.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.#cctor">
<summary>Temporary support for disabling crashing if tasks go unobserved.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.PreventUnobservedTaskExceptions">
<summary>Registers with UnobservedTaskException to suppress exception crashing.</summary>
</member>
<member name="F:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.s_preventUnobservedTaskExceptionsInvoked">
<summary>Non-zero if PreventUnobservedTaskExceptions has already been invoked.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Create">
<summary>Initializes a new <see cref="T:System.Runtime.CompilerServices.AsyncVoidMethodBuilder"/>.</summary>
<returns>The initialized <see cref="T:System.Runtime.CompilerServices.AsyncVoidMethodBuilder"/>.</returns>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.#ctor(System.Threading.SynchronizationContext)">
<summary>Initializes the <see cref="T:System.Runtime.CompilerServices.AsyncVoidMethodBuilder"/>.</summary>
<param name="synchronizationContext">The synchronizationContext associated with this operation. This may be null.</param>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Start``1(``0@)">
<summary>Initiates the builder's execution with the associated state machine.</summary>
<typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
<param name="stateMachine">The state machine instance, passed by reference.</param>
<exception cref="T:System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)">
<summary>Associates the builder with the state machine it represents.</summary>
<param name="stateMachine">The heap-allocated state machine object.</param>
<exception cref="T:System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
<exception cref="T:System.InvalidOperationException">The builder is incorrectly initialized.</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.System#Runtime#CompilerServices#IAsyncMethodBuilder#PreBoxInitialization">
<summary>Perform any initialization necessary prior to lifting the builder to the heap.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.AwaitOnCompleted``2(``0@,``1@)">
<summary>
Schedules the specified state machine to be pushed forward when the specified awaiter completes.
</summary>
<typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
<typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
<param name="awaiter">The awaiter.</param>
<param name="stateMachine">The state machine.</param>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.AwaitUnsafeOnCompleted``2(``0@,``1@)">
<summary>
Schedules the specified state machine to be pushed forward when the specified awaiter completes.
</summary>
<typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
<typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
<param name="awaiter">The awaiter.</param>
<param name="stateMachine">The state machine.</param>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetResult">
<summary>Completes the method builder successfully.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetException(System.Exception)">
<summary>Faults the method builder with an exception.</summary>
<param name="exception">The exception that is the cause of this fault.</param>
<exception cref="T:System.ArgumentNullException">The <paramref name="exception"/> argument is null (Nothing in Visual Basic).</exception>
<exception cref="T:System.InvalidOperationException">The builder is not initialized.</exception>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.NotifySynchronizationContextOfCompletion">
<summary>Notifies the current synchronization context that the operation completed.</summary>
</member>
<member name="P:System.Runtime.CompilerServices.AsyncVoidMethodBuilder.ObjectIdForDebugger">
<summary>
Gets an object that may be used to uniquely identify this builder to the debugger.
</summary>
<remarks>
This property lazily instantiates the ID in a non-thread-safe manner.
It must only be used by the debugger and only in a single-threaded manner.
</remarks>
</member>
<member name="T:System.Runtime.CompilerServices.IAsyncStateMachine">
<summary>
Represents state machines generated for asynchronous methods.
This type is intended for compiler use only.
</summary>
</member>
<member name="M:System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext">
<summary>Moves the state machine to its next state.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.IAsyncStateMachine.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)">
<summary>Configures the state machine with a heap-allocated replica.</summary>
<param name="stateMachine">The heap-allocated replica.</param>
</member>
<member name="T:System.Runtime.CompilerServices.ICriticalNotifyCompletion">
<summary>
Represents an awaiter used to schedule continuations when an await operation completes.
</summary>
</member>
<member name="T:System.Runtime.CompilerServices.INotifyCompletion">
<summary>
Represents an operation that will schedule continuations when the operation completes.
</summary>
</member>
<member name="M:System.Runtime.CompilerServices.INotifyCompletion.OnCompleted(System.Action)">
<summary>Schedules the continuation action to be invoked when the instance completes.</summary>
<param name="continuation">The action to invoke when the operation completes.</param>
<exception cref="T:System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
</member>
<member name="M:System.Runtime.CompilerServices.ICriticalNotifyCompletion.UnsafeOnCompleted(System.Action)">
<summary>Schedules the continuation action to be invoked when the instance completes.</summary>
<param name="continuation">The action to invoke when the operation completes.</param>
<exception cref="T:System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
<remarks>Unlike OnCompleted, UnsafeOnCompleted need not propagate ExecutionContext information.</remarks>
</member>
<member name="T:System.Runtime.CompilerServices.VoidTaskResult">
<summary>Used with Task(of void)</summary>
</member>
</members>
</doc>

0
src/packages/Microsoft.Bcl.1.0.16-rc/lib/net45/_._

BIN
src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp71/System.Runtime.dll

Binary file not shown.

860
src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp71/System.Runtime.xml

@ -0,0 +1,860 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>System.Runtime</name>
</assembly>
<members>
<member name="T:System.Strings">
<summary>
A strongly-typed resource class, for looking up localized strings, etc.
</summary>
</member>
<member name="P:System.Strings.ResourceManager">
<summary>
Returns the cached ResourceManager instance used by this class.
</summary>
</member>
<member name="P:System.Strings.Culture">
<summary>
Overrides the current thread's CurrentUICulture property for all
resource lookups using this strongly typed resource class.
</summary>
</member>
<member name="P:System.Strings.ArgumentException_TupleIncorrectType">
<summary>
Looks up a localized string similar to Argument must be of type {0}..
</summary>
</member>
<member name="P:System.Strings.ArgumentException_TupleLastArgumentNotATuple">
<summary>
Looks up a localized string similar to The last element of an eight element tuple must be a Tuple..
</summary>
</member>
<member name="T:System.Collections.IStructuralEquatable">
<summary>
Defines methods to support the comparison of objects for structural equality.
</summary>
</member>
<member name="M:System.Collections.IStructuralEquatable.Equals(System.Object,System.Collections.IEqualityComparer)">
<summary>
Determines whether an object is structurally equal to the current instance.
</summary>
<param name="other">The object to compare with the current instance.</param>
<param name="comparer">An object that determines whether the current instance and other are equal. </param>
<returns>true if the two objects are equal; otherwise, false.</returns>
</member>
<member name="M:System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer)">
<summary>
Returns a hash code for the current instance.
</summary>
<param name="comparer">An object that computes the hash code of the current object.</param>
<returns>The hash code for the current instance.</returns>
</member>
<member name="T:System.Collections.IStructuralComparable">
<summary>
Supports the structural comparison of collection objects.
</summary>
</member>
<member name="M:System.Collections.IStructuralComparable.CompareTo(System.Object,System.Collections.IComparer)">
<summary>
Determines whether the current collection object precedes, occurs in the same position as, or follows another object in the sort order.
</summary>
<param name="other">The object to compare with the current instance.</param>
<param name="comparer">An object that compares members of the current collection object with the corresponding members of other.</param>
<returns>An integer that indicates the relationship of the current collection object to other.</returns>
<exception cref="T:System.ArgumentException">
This instance and other are not the same type.
</exception>
</member>
<member name="T:System.Func`6">
<summary>
Encapsulates a method that has five parameters and returns a value of the type specified by the TResult parameter.
</summary>
<typeparam name="T1">The type of the first parameter of the method that this delegate encapsulates.</typeparam>
<typeparam name="T2">The type of the second parameter of the method that this delegate encapsulates.</typeparam>
<typeparam name="T3">The type of the third parameter of the method that this delegate encapsulates.</typeparam>
<typeparam name="T4">The type of the fourth parameter of the method that this delegate encapsulates.</typeparam>
<typeparam name="T5">The type of the fifth parameter of the method that this delegate encapsulates.</typeparam>
<typeparam name="TResult">The type of the return value of the method that this delegate encapsulates.</typeparam>
<param name="arg1">The first parameter of the method that this delegate encapsulates.</param>
<param name="arg2">The second parameter of the method that this delegate encapsulates.</param>
<param name="arg3">The third parameter of the method that this delegate encapsulates.</param>
<param name="arg4">The fourth parameter of the method that this delegate encapsulates.</param>
<param name="arg5">The fifth parameter of the method that this delegate encapsulates.</param>
<returns>The return value of the method that this delegate encapsulates.</returns>
</member>
<member name="T:System.IProgress`1">
<summary>Defines a provider for progress updates.</summary>
<typeparam name="T">The type of progress update value.</typeparam>
</member>
<member name="M:System.IProgress`1.Report(`0)">
<summary>Reports a progress update.</summary>
<param name="value">The value of the updated progress.</param>
</member>
<member name="T:System.Runtime.CompilerServices.AsyncStateMachineAttribute">
<summary>Identities the async state machine type for this method.</summary>
</member>
<member name="T:System.Runtime.CompilerServices.StateMachineAttribute">
<summary>Identities the state machine type for this method.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.StateMachineAttribute.#ctor(System.Type)">
<summary>Initializes the attribute.</summary>
<param name="stateMachineType">The type that implements the state machine.</param>
</member>
<member name="P:System.Runtime.CompilerServices.StateMachineAttribute.StateMachineType">
<summary>Gets the type that implements the state machine.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncStateMachineAttribute.#ctor(System.Type)">
<summary>Initializes the attribute.</summary>
<param name="stateMachineType">The type that implements the state machine.</param>
</member>
<member name="T:System.Runtime.CompilerServices.CallerMemberNameAttribute">
<summary>
Allows you to obtain the method or property name of the caller to the method.
</summary>
</member>
<member name="T:System.Runtime.CompilerServices.CallerLineNumberAttribute">
<summary>
Allows you to obtain the line number in the source file at which the method is called.
</summary>
</member>
<member name="T:System.Runtime.CompilerServices.CallerFilePathAttribute">
<summary>
Allows you to obtain the full path of the source file that contains the caller.
This is the file path at the time of compile.
</summary>
</member>
<member name="T:System.Runtime.CompilerServices.IteratorStateMachineAttribute">
<summary>Identities the iterator state machine type for this method.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.IteratorStateMachineAttribute.#ctor(System.Type)">
<summary>Initializes the attribute.</summary>
<param name="stateMachineType">The type that implements the state machine.</param>
</member>
<member name="T:System.ITuple">
<summary>
Helper so we can call some tuple methods recursively without knowing the underlying types.
</summary>
</member>
<member name="T:System.Tuple">
<summary>
Provides static methods for creating tuple objects.
</summary>
</member>
<member name="M:System.Tuple.Create``1(``0)">
<summary>
Creates a new 1-tuple, or singleton.
</summary>
<typeparam name="T1">The type of the only component of the tuple.</typeparam>
<param name="item1">The value of the only component of the tuple.</param>
<returns>A tuple whose value is (item1).</returns>
</member>
<member name="M:System.Tuple.Create``2(``0,``1)">
<summary>
Creates a new 3-tuple, or pair.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<returns>An 2-tuple (pair) whose value is (item1, item2).</returns>
</member>
<member name="M:System.Tuple.Create``3(``0,``1,``2)">
<summary>
Creates a new 3-tuple, or triple.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
<returns>An 3-tuple (triple) whose value is (item1, item2, item3).</returns>
</member>
<member name="M:System.Tuple.Create``4(``0,``1,``2,``3)">
<summary>
Creates a new 4-tuple, or quadruple.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
<typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
<param name="item4">The value of the fourth component of the tuple.</param>
<returns>An 4-tuple (quadruple) whose value is (item1, item2, item3, item4).</returns>
</member>
<member name="M:System.Tuple.Create``5(``0,``1,``2,``3,``4)">
<summary>
Creates a new 5-tuple, or quintuple.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
<typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
<typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
<param name="item4">The value of the fourth component of the tuple.</param>
<param name="item5">The value of the fifth component of the tuple.</param>
<returns>An 5-tuple (quintuple) whose value is (item1, item2, item3, item4, item5).</returns>
</member>
<member name="M:System.Tuple.Create``6(``0,``1,``2,``3,``4,``5)">
<summary>
Creates a new 6-tuple, or sextuple.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
<typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
<typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
<typeparam name="T6">The type of the sixth component of the tuple.</typeparam>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
<param name="item4">The value of the fourth component of the tuple.</param>
<param name="item5">The value of the fifth component of the tuple.</param>
<param name="item6">The value of the sixth component of the tuple.</param>
<returns>An 6-tuple (sextuple) whose value is (item1, item2, item3, item4, item5, item6).</returns>
</member>
<member name="M:System.Tuple.Create``7(``0,``1,``2,``3,``4,``5,``6)">
<summary>
Creates a new 7-tuple, or septuple.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
<typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
<typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
<typeparam name="T6">The type of the sixth component of the tuple.</typeparam>
<typeparam name="T7">The type of the seventh component of the tuple.</typeparam>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
<param name="item4">The value of the fourth component of the tuple.</param>
<param name="item5">The value of the fifth component of the tuple.</param>
<param name="item6">The value of the sixth component of the tuple.</param>
<param name="item7">The value of the seventh component of the tuple.</param>
<returns>An 7-tuple (septuple) whose value is (item1, item2, item3, item4, item5, item6, item7).</returns>
</member>
<member name="M:System.Tuple.Create``8(``0,``1,``2,``3,``4,``5,``6,``7)">
<summary>
Creates a new 8-tuple, or octuple.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
<typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
<typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
<typeparam name="T6">The type of the sixth component of the tuple.</typeparam>
<typeparam name="T7">The type of the seventh component of the tuple.</typeparam>
<typeparam name="T8">The type of the eighth component of the tuple.</typeparam>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
<param name="item4">The value of the fourth component of the tuple.</param>
<param name="item5">The value of the fifth component of the tuple.</param>
<param name="item6">The value of the sixth component of the tuple.</param>
<param name="item7">The value of the seventh component of the tuple.</param>
<param name="item8">The value of the eighth component of the tuple.</param>
<returns>An 8-tuple (octuple) whose value is (item1, item2, item3, item4, item5, item6, item7, item8).</returns>
</member>
<member name="T:System.Tuple`1">
<summary>
Represents a 1-tuple, or singleton.
</summary>
<typeparam name="T1">The type of the tuple's only component.</typeparam>
</member>
<member name="M:System.Tuple`1.#ctor(`0)">
<summary>
Initializes a new instance of the <see cref="T:System.Tuple`1"/> class.
</summary>
<param name="item1">The value of the current tuple object's single component.</param>
</member>
<member name="M:System.Tuple`1.Equals(System.Object)">
<summary>
Returns a value that indicates whether the current tuple object is equal to a specified object.
</summary>
<param name="obj">The object to compare with this instance.</param>
<returns>true if the current instance is equal to the specified object; otherwise, false.</returns>
</member>
<member name="M:System.Tuple`1.GetHashCode">
<summary>
Calculates the hash code for the current tuple object.
</summary>
<returns>A 32-bit signed integer hash code.</returns>
</member>
<member name="M:System.Tuple`1.ToString">
<summary>
Returns a string that represents the value of this tuple instance.
</summary>
<returns>The string representation of this tuple object.</returns>
</member>
<member name="P:System.Tuple`1.Item1">
<summary>
Gets the value of the tuple object's single component.
</summary>
<value>
The value of the current tuple object's single component.
</value>
</member>
<member name="T:System.Tuple`2">
<summary>
Represents an 2-tuple, or pair.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
</member>
<member name="M:System.Tuple`2.#ctor(`0,`1)">
<summary>
Initializes a new instance of the <see cref="T:System.Tuple`2"/> class.
</summary>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
</member>
<member name="M:System.Tuple`2.Equals(System.Object)">
<summary>
Returns a value that indicates whether the current tuple object is equal to a specified object.
</summary>
<param name="obj">The object to compare with this instance.</param>
<returns>true if the current instance is equal to the specified object; otherwise, false.</returns>
</member>
<member name="M:System.Tuple`2.GetHashCode">
<summary>
Calculates the hash code for the current tuple object.
</summary>
<returns>A 32-bit signed integer hash code.</returns>
</member>
<member name="M:System.Tuple`2.ToString">
<summary>
Returns a string that represents the value of this tuple instance.
</summary>
<returns>The string representation of this tuple object.</returns>
</member>
<member name="P:System.Tuple`2.Item1">
<summary>
Gets the value of the current tuple object's first component.
</summary>
<value>
The value of the current tuple object's first component.
</value>
</member>
<member name="P:System.Tuple`2.Item2">
<summary>
Gets the value of the current tuple object's second component.
</summary>
<value>
The value of the current tuple object's second component.
</value>
</member>
<member name="T:System.Tuple`3">
<summary>
Represents an 3-tuple, or triple.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
</member>
<member name="M:System.Tuple`3.#ctor(`0,`1,`2)">
<summary>
Initializes a new instance of the <see cref="T:System.Tuple`3"/> class.
</summary>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
</member>
<member name="M:System.Tuple`3.Equals(System.Object)">
<summary>
Returns a value that indicates whether the current tuple object is equal to a specified object.
</summary>
<param name="obj">The object to compare with this instance.</param>
<returns>true if the current instance is equal to the specified object; otherwise, false.</returns>
</member>
<member name="M:System.Tuple`3.GetHashCode">
<summary>
Calculates the hash code for the current tuple object.
</summary>
<returns>A 32-bit signed integer hash code.</returns>
</member>
<member name="M:System.Tuple`3.ToString">
<summary>
Returns a string that represents the value of this tuple instance.
</summary>
<returns>The string representation of this tuple object.</returns>
</member>
<member name="P:System.Tuple`3.Item1">
<summary>
Gets the value of the current tuple object's first component.
</summary>
<value>
The value of the current tuple object's first component.
</value>
</member>
<member name="P:System.Tuple`3.Item2">
<summary>
Gets the value of the current tuple object's second component.
</summary>
<value>
The value of the current tuple object's second component.
</value>
</member>
<member name="P:System.Tuple`3.Item3">
<summary>
Gets the value of the current tuple object's third component.
</summary>
<value>
The value of the current tuple object's third component.
</value>
</member>
<member name="T:System.Tuple`4">
<summary>
Represents an 4-tuple, or quadruple.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
<typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
</member>
<member name="M:System.Tuple`4.#ctor(`0,`1,`2,`3)">
<summary>
Initializes a new instance of the <see cref="T:System.Tuple`4"/> class.
</summary>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
<param name="item4">The value of the fourth component of the tuple.</param>
</member>
<member name="M:System.Tuple`4.Equals(System.Object)">
<summary>
Returns a value that indicates whether the current tuple object is equal to a specified object.
</summary>
<param name="obj">The object to compare with this instance.</param>
<returns>true if the current instance is equal to the specified object; otherwise, false.</returns>
</member>
<member name="M:System.Tuple`4.GetHashCode">
<summary>
Calculates the hash code for the current tuple object.
</summary>
<returns>A 32-bit signed integer hash code.</returns>
</member>
<member name="M:System.Tuple`4.ToString">
<summary>
Returns a string that represents the value of this tuple instance.
</summary>
<returns>The string representation of this tuple object.</returns>
</member>
<member name="P:System.Tuple`4.Item1">
<summary>
Gets the value of the current tuple object's first component.
</summary>
<value>
The value of the current tuple object's first component.
</value>
</member>
<member name="P:System.Tuple`4.Item2">
<summary>
Gets the value of the current tuple object's second component.
</summary>
<value>
The value of the current tuple object's second component.
</value>
</member>
<member name="P:System.Tuple`4.Item3">
<summary>
Gets the value of the current tuple object's third component.
</summary>
<value>
The value of the current tuple object's third component.
</value>
</member>
<member name="P:System.Tuple`4.Item4">
<summary>
Gets the value of the current tuple object's fourth component.
</summary>
<value>
The value of the current tuple object's fourth component.
</value>
</member>
<member name="T:System.Tuple`5">
<summary>
Represents an 5-tuple, or quintuple.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
<typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
<typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
</member>
<member name="M:System.Tuple`5.#ctor(`0,`1,`2,`3,`4)">
<summary>
Initializes a new instance of the <see cref="T:System.Tuple`5"/> class.
</summary>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
<param name="item4">The value of the fourth component of the tuple.</param>
<param name="item5">The value of the fifth component of the tuple.</param>
</member>
<member name="M:System.Tuple`5.Equals(System.Object)">
<summary>
Returns a value that indicates whether the current tuple object is equal to a specified object.
</summary>
<param name="obj">The object to compare with this instance.</param>
<returns>true if the current instance is equal to the specified object; otherwise, false.</returns>
</member>
<member name="M:System.Tuple`5.GetHashCode">
<summary>
Calculates the hash code for the current tuple object.
</summary>
<returns>A 32-bit signed integer hash code.</returns>
</member>
<member name="M:System.Tuple`5.ToString">
<summary>
Returns a string that represents the value of this tuple instance.
</summary>
<returns>The string representation of this tuple object.</returns>
</member>
<member name="P:System.Tuple`5.Item1">
<summary>
Gets the value of the current tuple object's first component.
</summary>
<value>
The value of the current tuple object's first component.
</value>
</member>
<member name="P:System.Tuple`5.Item2">
<summary>
Gets the value of the current tuple object's second component.
</summary>
<value>
The value of the current tuple object's second component.
</value>
</member>
<member name="P:System.Tuple`5.Item3">
<summary>
Gets the value of the current tuple object's third component.
</summary>
<value>
The value of the current tuple object's third component.
</value>
</member>
<member name="P:System.Tuple`5.Item4">
<summary>
Gets the value of the current tuple object's fourth component.
</summary>
<value>
The value of the current tuple object's fourth component.
</value>
</member>
<member name="P:System.Tuple`5.Item5">
<summary>
Gets the value of the current tuple object's fifth component.
</summary>
<value>
The value of the current tuple object's fifth component.
</value>
</member>
<member name="T:System.Tuple`6">
<summary>
Represents an 6-tuple, or sextuple.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
<typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
<typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
<typeparam name="T6">The type of the sixth component of the tuple.</typeparam>
</member>
<member name="M:System.Tuple`6.#ctor(`0,`1,`2,`3,`4,`5)">
<summary>
Initializes a new instance of the <see cref="T:System.Tuple`6"/> class.
</summary>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
<param name="item4">The value of the fourth component of the tuple.</param>
<param name="item5">The value of the fifth component of the tuple.</param>
<param name="item6">The value of the sixth component of the tuple.</param>
</member>
<member name="M:System.Tuple`6.Equals(System.Object)">
<summary>
Returns a value that indicates whether the current tuple object is equal to a specified object.
</summary>
<param name="obj">The object to compare with this instance.</param>
<returns>true if the current instance is equal to the specified object; otherwise, false.</returns>
</member>
<member name="M:System.Tuple`6.GetHashCode">
<summary>
Calculates the hash code for the current tuple object.
</summary>
<returns>A 32-bit signed integer hash code.</returns>
</member>
<member name="M:System.Tuple`6.ToString">
<summary>
Returns a string that represents the value of this tuple instance.
</summary>
<returns>The string representation of this tuple object.</returns>
</member>
<member name="P:System.Tuple`6.Item1">
<summary>
Gets the value of the current tuple object's first component.
</summary>
<value>
The value of the current tuple object's first component.
</value>
</member>
<member name="P:System.Tuple`6.Item2">
<summary>
Gets the value of the current tuple object's second component.
</summary>
<value>
The value of the current tuple object's second component.
</value>
</member>
<member name="P:System.Tuple`6.Item3">
<summary>
Gets the value of the current tuple object's third component.
</summary>
<value>
The value of the current tuple object's third component.
</value>
</member>
<member name="P:System.Tuple`6.Item4">
<summary>
Gets the value of the current tuple object's fourth component.
</summary>
<value>
The value of the current tuple object's fourth component.
</value>
</member>
<member name="P:System.Tuple`6.Item5">
<summary>
Gets the value of the current tuple object's fifth component.
</summary>
<value>
The value of the current tuple object's fifth component.
</value>
</member>
<member name="P:System.Tuple`6.Item6">
<summary>
Gets the value of the current tuple object's sixth component.
</summary>
<value>
The value of the current tuple object's sixth component.
</value>
</member>
<member name="T:System.Tuple`7">
<summary>
Represents an 7-tuple, or septuple.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
<typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
<typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
<typeparam name="T6">The type of the sixth component of the tuple.</typeparam>
<typeparam name="T7">The type of the seventh component of the tuple.</typeparam>
</member>
<member name="M:System.Tuple`7.#ctor(`0,`1,`2,`3,`4,`5,`6)">
<summary>
Initializes a new instance of the <see cref="T:System.Tuple`7"/> class.
</summary>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
<param name="item4">The value of the fourth component of the tuple.</param>
<param name="item5">The value of the fifth component of the tuple.</param>
<param name="item6">The value of the sixth component of the tuple.</param>
<param name="item7">The value of the seventh component of the tuple.</param>
</member>
<member name="M:System.Tuple`7.Equals(System.Object)">
<summary>
Returns a value that indicates whether the current tuple object is equal to a specified object.
</summary>
<param name="obj">The object to compare with this instance.</param>
<returns>true if the current instance is equal to the specified object; otherwise, false.</returns>
</member>
<member name="M:System.Tuple`7.GetHashCode">
<summary>
Calculates the hash code for the current tuple object.
</summary>
<returns>A 32-bit signed integer hash code.</returns>
</member>
<member name="M:System.Tuple`7.ToString">
<summary>
Returns a string that represents the value of this tuple instance.
</summary>
<returns>The string representation of this tuple object.</returns>
</member>
<member name="P:System.Tuple`7.Item1">
<summary>
Gets the value of the current tuple object's first component.
</summary>
<value>
The value of the current tuple object's first component.
</value>
</member>
<member name="P:System.Tuple`7.Item2">
<summary>
Gets the value of the current tuple object's second component.
</summary>
<value>
The value of the current tuple object's second component.
</value>
</member>
<member name="P:System.Tuple`7.Item3">
<summary>
Gets the value of the current tuple object's third component.
</summary>
<value>
The value of the current tuple object's third component.
</value>
</member>
<member name="P:System.Tuple`7.Item4">
<summary>
Gets the value of the current tuple object's fourth component.
</summary>
<value>
The value of the current tuple object's fourth component.
</value>
</member>
<member name="P:System.Tuple`7.Item5">
<summary>
Gets the value of the current tuple object's fifth component.
</summary>
<value>
The value of the current tuple object's fifth component.
</value>
</member>
<member name="P:System.Tuple`7.Item6">
<summary>
Gets the value of the current tuple object's sixth component.
</summary>
<value>
The value of the current tuple object's sixth component.
</value>
</member>
<member name="P:System.Tuple`7.Item7">
<summary>
Gets the value of the current tuple object's seventh component.
</summary>
<value>
The value of the current tuple object's seventh component.
</value>
</member>
<member name="T:System.Tuple`8">
<summary>
Represents an n-tuple, where n is 8 or greater.
</summary>
<typeparam name="T1">The type of the first component of the tuple.</typeparam>
<typeparam name="T2">The type of the second component of the tuple.</typeparam>
<typeparam name="T3">The type of the third component of the tuple.</typeparam>
<typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
<typeparam name="T5">The type of the fifth component of the tuple.</typeparam>
<typeparam name="T6">The type of the sixth component of the tuple.</typeparam>
<typeparam name="T7">The type of the seventh component of the tuple.</typeparam>
<typeparam name="TRest">Any generic Tuple object that defines the types of the tuple's remaining components.</typeparam>
</member>
<member name="M:System.Tuple`8.#ctor(`0,`1,`2,`3,`4,`5,`6,`7)">
<summary>
Initializes a new instance of the <see cref="T:System.Tuple`8"/> class.
</summary>
<param name="item1">The value of the first component of the tuple.</param>
<param name="item2">The value of the second component of the tuple.</param>
<param name="item3">The value of the third component of the tuple.</param>
<param name="item4">The value of the fourth component of the tuple.</param>
<param name="item5">The value of the fifth component of the tuple.</param>
<param name="item6">The value of the sixth component of the tuple.</param>
<param name="item7">The value of the seventh component of the tuple.</param>
<param name="rest">Any generic Tuple object that contains the values of the tuple's remaining components.</param>
<exception cref="T:System.ArgumentException">
rest is not a generic Tuple object.
</exception>
</member>
<member name="M:System.Tuple`8.Equals(System.Object)">
<summary>
Returns a value that indicates whether the current tuple object is equal to a specified object.
</summary>
<param name="obj">The object to compare with this instance.</param>
<returns>true if the current instance is equal to the specified object; otherwise, false.</returns>
</member>
<member name="M:System.Tuple`8.GetHashCode">
<summary>
Calculates the hash code for the current tuple object.
</summary>
<returns>A 32-bit signed integer hash code.</returns>
</member>
<member name="M:System.Tuple`8.ToString">
<summary>
Returns a string that represents the value of this tuple instance.
</summary>
<returns>The string representation of this tuple object.</returns>
</member>
<member name="P:System.Tuple`8.Item1">
<summary>
Gets the value of the current tuple object's first component.
</summary>
<value>
The value of the current tuple object's first component.
</value>
</member>
<member name="P:System.Tuple`8.Item2">
<summary>
Gets the value of the current tuple object's second component.
</summary>
<value>
The value of the current tuple object's second component.
</value>
</member>
<member name="P:System.Tuple`8.Item3">
<summary>
Gets the value of the current tuple object's third component.
</summary>
<value>
The value of the current tuple object's third component.
</value>
</member>
<member name="P:System.Tuple`8.Item4">
<summary>
Gets the value of the current tuple object's fourth component.
</summary>
<value>
The value of the current tuple object's fourth component.
</value>
</member>
<member name="P:System.Tuple`8.Item5">
<summary>
Gets the value of the current tuple object's fifth component.
</summary>
<value>
The value of the current tuple object's fifth component.
</value>
</member>
<member name="P:System.Tuple`8.Item6">
<summary>
Gets the value of the current tuple object's sixth component.
</summary>
<value>
The value of the current tuple object's sixth component.
</value>
</member>
<member name="P:System.Tuple`8.Item7">
<summary>
Gets the value of the current tuple object's seventh component.
</summary>
<value>
The value of the current tuple object's seventh component.
</value>
</member>
<member name="P:System.Tuple`8.Rest">
<summary>
Gets the current tuple object's remaining components.
</summary>
<value>
The value of the current tuple object's remaining components.
</value>
</member>
</members>
</doc>

1
src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp71/System.Threading.Tasks.dll.REMOVED.git-id

@ -0,0 +1 @@
9962594785f41f62455059efef8b8007e719a054

1
src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp71/System.Threading.Tasks.xml.REMOVED.git-id

@ -0,0 +1 @@
6c770122e85766385d4408b770fac43f117b065a

BIN
src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp8/System.Runtime.dll

Binary file not shown.

56
src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp8/System.Runtime.xml

@ -0,0 +1,56 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>System.Runtime</name>
</assembly>
<members>
<member name="T:System.IProgress`1">
<summary>Defines a provider for progress updates.</summary>
<typeparam name="T">The type of progress update value.</typeparam>
</member>
<member name="M:System.IProgress`1.Report(`0)">
<summary>Reports a progress update.</summary>
<param name="value">The value of the updated progress.</param>
</member>
<member name="T:System.Runtime.CompilerServices.AsyncStateMachineAttribute">
<summary>Identities the async state machine type for this method.</summary>
</member>
<member name="T:System.Runtime.CompilerServices.StateMachineAttribute">
<summary>Identities the state machine type for this method.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.StateMachineAttribute.#ctor(System.Type)">
<summary>Initializes the attribute.</summary>
<param name="stateMachineType">The type that implements the state machine.</param>
</member>
<member name="P:System.Runtime.CompilerServices.StateMachineAttribute.StateMachineType">
<summary>Gets the type that implements the state machine.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.AsyncStateMachineAttribute.#ctor(System.Type)">
<summary>Initializes the attribute.</summary>
<param name="stateMachineType">The type that implements the state machine.</param>
</member>
<member name="T:System.Runtime.CompilerServices.CallerMemberNameAttribute">
<summary>
Allows you to obtain the method or property name of the caller to the method.
</summary>
</member>
<member name="T:System.Runtime.CompilerServices.CallerLineNumberAttribute">
<summary>
Allows you to obtain the line number in the source file at which the method is called.
</summary>
</member>
<member name="T:System.Runtime.CompilerServices.CallerFilePathAttribute">
<summary>
Allows you to obtain the full path of the source file that contains the caller.
This is the file path at the time of compile.
</summary>
</member>
<member name="T:System.Runtime.CompilerServices.IteratorStateMachineAttribute">
<summary>Identities the iterator state machine type for this method.</summary>
</member>
<member name="M:System.Runtime.CompilerServices.IteratorStateMachineAttribute.#ctor(System.Type)">
<summary>Initializes the attribute.</summary>
<param name="stateMachineType">The type that implements the state machine.</param>
</member>
</members>
</doc>

1
src/packages/Microsoft.Bcl.1.0.16-rc/lib/portable-net40+sl4+win8+wp8/System.Threading.Tasks.dll.REMOVED.git-id

@ -0,0 +1 @@
9962594785f41f62455059efef8b8007e719a054

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save