Browse Source

new caching system using SQLite

Former-commit-id: c9a426196af89eb6f303b13c1f025b04333dcbf3
af/merge-core
JimBobSquarePants 13 years ago
parent
commit
9ace78ed58
  1. 101
      src/ImageProcessor.Tests/ImageProcessor.Tests.csproj
  2. 36
      src/ImageProcessor.Tests/Properties/AssemblyInfo.cs
  3. 18
      src/ImageProcessor.Tests/UnitTest1.cs
  4. 39
      src/ImageProcessor.Web/Caching/CachedImage.cs
  5. 82
      src/ImageProcessor.Web/Caching/DiskCache.cs
  6. 2
      src/ImageProcessor.Web/Caching/LockedDictionary.cs
  7. 107
      src/ImageProcessor.Web/Caching/PersistantDictionary.cs
  8. 216
      src/ImageProcessor.Web/Caching/SQLContext.cs
  9. 28
      src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs
  10. 40
      src/ImageProcessor.Web/ImageProcessor.Web.csproj
  11. 4
      src/ImageProcessor.Web/packages.config
  12. 37
      src/ImageProcessor.sln
  13. 31
      src/ImageProcessor/ImageProcessor.csproj
  14. 32
      src/Test/Test/Controllers/HomeController.cs
  15. 30
      src/Test/Test/Test.csproj
  16. 20
      src/Test/Test/Views/Home/Speed.cshtml
  17. 2
      src/Test/Test/Web.config
  18. 1
      src/packages/System.Data.SQLite.x86.1.0.84.0/System.Data.SQLite.x86.1.0.84.0.nupkg.REMOVED.git-id
  19. 23
      src/packages/System.Data.SQLite.x86.1.0.84.0/System.Data.SQLite.x86.1.0.84.0.nuspec
  20. 1
      src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net20/System.Data.SQLite.Linq.dll.REMOVED.git-id
  21. 1
      src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net20/System.Data.SQLite.dll.REMOVED.git-id
  22. 1
      src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net40/System.Data.SQLite.Linq.dll.REMOVED.git-id
  23. 1
      src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net40/System.Data.SQLite.dll.REMOVED.git-id
  24. 1
      src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net45/System.Data.SQLite.Linq.dll.REMOVED.git-id
  25. 1
      src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net45/System.Data.SQLite.dll.REMOVED.git-id
  26. 4
      src/packages/repositories.config

101
src/ImageProcessor.Tests/ImageProcessor.Tests.csproj

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{39911A38-CA06-413C-80AA-39EF60CE984F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ImageProcessor.Tests</RootNamespace>
<AssemblyName>ImageProcessor.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="UnitTest1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- 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.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

36
src/ImageProcessor.Tests/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ImageProcessor.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ImageProcessor.Tests")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ab617b65-7259-4dc5-9dad-81a7c6537a4f")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

18
src/ImageProcessor.Tests/UnitTest1.cs

@ -0,0 +1,18 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ImageProcessor.Tests
{
using System.IO;
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
}
}
}

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

@ -14,53 +14,40 @@ namespace ImageProcessor.Web.Caching
/// <summary>
/// Describes a cached image
/// </summary>
public class CachedImage
internal sealed class CachedImage
{
/// <summary>
/// Initializes a new instance of the <see cref="CachedImage"/> class.
/// </summary>
/// <param name="value">
/// <param name="path">
/// The value of the cached item.
/// </param>
/// <param name="lastWriteTimeUtc">
/// The last write time of the cached item.
/// </param>
public CachedImage(string value, DateTime lastWriteTimeUtc)
/// <param name="expiresTimeUtc">
/// The expires time.
/// </param>
public CachedImage(string path, DateTime lastWriteTimeUtc, DateTime expiresTimeUtc)
{
this.Value = value;
this.Path = path;
this.LastWriteTimeUtc = lastWriteTimeUtc;
this.ExpiresUtc = expiresTimeUtc;
}
/// <summary>
/// Gets the value date time delimiter.
/// </summary>
public static string ValueLastWriteTimeDelimiter
{
get
{
return "|*|";
}
}
/// <summary>
/// Gets or sets the value of the cached item
/// Gets or sets the value of the cached image
/// </summary>
public string Value { get; set; }
public string Path { get; set; }
/// <summary>
/// Gets or sets the last write time of the cached item
/// Gets or sets the last write time of the cached image
/// </summary>
public DateTime LastWriteTimeUtc { get; set; }
/// <summary>
/// The value and last write time as a string.
/// Gets or sets when the cached image should expire from the cache.
/// </summary>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
public string ValueAndLastWriteTimeUtcToString()
{
return string.Format("{0}{1}{2}", this.Value, ValueLastWriteTimeDelimiter, this.LastWriteTimeUtc);
}
public DateTime ExpiresUtc { get; set; }
}
}

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

@ -19,7 +19,6 @@ namespace ImageProcessor.Web.Caching
using System.Web.Hosting;
using ImageProcessor.Helpers.Extensions;
using ImageProcessor.Web.Config;
using ImageProcessor.Web.Helpers;
#endregion
/// <summary>
@ -111,6 +110,23 @@ namespace ImageProcessor.Web.Caching
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 = lastWriteTimeUtc.AddDays(MaxFileCachedDuration).ToUniversalTime();
CachedImage cachedImage = new CachedImage(key, lastWriteTimeUtc, expires);
PersistantDictionary.Instance.Add(key, cachedImage);
}
/// <summary>
/// Converts an absolute file path
/// </summary>
@ -155,12 +171,14 @@ namespace ImageProcessor.Web.Caching
/// </returns>
internal static bool IsUpdatedFile(string imagePath, string cachedImagePath)
{
if (File.Exists(imagePath) && File.Exists(cachedImagePath))
if (File.Exists(imagePath))
{
CachedImage image;
string key = Path.GetFileNameWithoutExtension(cachedImagePath);
PersistantDictionary.Instance.TryGetValue(key, out image);
FileInfo imageFileInfo = new FileInfo(imagePath);
FileInfo cachedImageFileInfo = new FileInfo(cachedImagePath);
return !new FileCompareLastwritetime().Equals(imageFileInfo, cachedImageFileInfo);
return image != null && imageFileInfo.LastWriteTimeUtc.Equals(image.LastWriteTimeUtc);
}
return true;
@ -169,18 +187,28 @@ namespace ImageProcessor.Web.Caching
/// <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>
internal static void SetCachedLastWriteTime(string imagePath, string cachedImagePath)
/// <param name="imagePath">
/// The original image path.
/// </param>
/// <param name="cachedImagePath">
/// The cached image path.
/// </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)
{
if (File.Exists(imagePath) && File.Exists(cachedImagePath))
lock (SyncRoot)
{
lock (SyncRoot)
if (File.Exists(imagePath) && File.Exists(cachedImagePath))
{
DateTime dateTime = File.GetLastWriteTimeUtc(imagePath);
File.SetLastWriteTimeUtc(cachedImagePath, dateTime);
return dateTime;
}
}
return DateTime.MinValue;
}
/// <summary>
@ -188,6 +216,24 @@ namespace ImageProcessor.Web.Caching
/// </summary>
private static void PurgeFolders()
{
Regex searchTerm = new Regex(@"(jpeg|png|bmp|gif)");
var list = PersistantDictionary.Instance.ToList()
.GroupBy(x => searchTerm.Match(x.Value.Path))
.Select(y => new
{
Path = y.Key,
Expires = y.Select(z => z.Value.ExpiresUtc),
Count = y.Sum(z => z.Key.Count())
})
.AsEnumerable();
foreach (var path in list)
{
}
string folder = HostingEnvironment.MapPath(CachePath);
if (folder != null)
@ -197,7 +243,7 @@ namespace ImageProcessor.Web.Caching
if (directoryInfo.Exists)
{
List<DirectoryInfo> directoryInfos = directoryInfo
.EnumerateDirectories("*", SearchOption.AllDirectories)
.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
.ToList();
Parallel.ForEach(
@ -205,7 +251,7 @@ namespace ImageProcessor.Web.Caching
subDirectoryInfo =>
{
// Get all the files in the cache ordered by LastAccessTime - oldest first.
List<FileInfo> fileInfos = subDirectoryInfo.EnumerateFiles("*", SearchOption.AllDirectories)
List<FileInfo> fileInfos = subDirectoryInfo.EnumerateFiles("*", SearchOption.TopDirectoryOnly)
.OrderBy(x => x.LastAccessTimeUtc).ToList();
int counter = fileInfos.Count;
@ -221,8 +267,18 @@ namespace ImageProcessor.Web.Caching
{
try
{
fileInfo.Delete();
counter -= 1;
// Remove from the cache.
string key = Path.GetFileNameWithoutExtension(fileInfo.Name);
CachedImage cachedImage;
if (PersistantDictionary.Instance.TryGetValue(key, out cachedImage))
{
if (PersistantDictionary.Instance.TryRemove(key, out cachedImage))
{
fileInfo.Delete();
counter -= 1;
}
}
}
catch (IOException)
{

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

@ -21,7 +21,7 @@ namespace ImageProcessor.Web.Caching
/// <typeparam name="TVal">
/// The type of the values in the dictionary.
/// </typeparam>
public class LockedDictionary<TKey, TVal> : IDictionary<TKey, TVal>
internal class LockedDictionary<TKey, TVal> : IDictionary<TKey, TVal>
{
/// <summary>
/// The _inner.

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

@ -9,16 +9,15 @@ namespace ImageProcessor.Web.Caching
{
#region Using
using System;
using System.IO;
using System.Web.Hosting;
using ImageProcessor.Web.Config;
using System.Collections.Generic;
#endregion
/// <summary>
/// Represents a collection of keys and values whose operations are concurrent.
/// </summary>
public class PersistantDictionary : LockedDictionary<string, CachedImage>
internal sealed class PersistantDictionary : LockedDictionary<string, CachedImage>
{
#region Fields
/// <summary>
/// A new instance Initializes a new instance of the <see cref="T:ImageProcessor.Web.Caching.PersistantDictionary"/> class.
/// initialized lazily.
@ -26,20 +25,11 @@ namespace ImageProcessor.Web.Caching
private static readonly Lazy<PersistantDictionary> Lazy =
new Lazy<PersistantDictionary>(() => new PersistantDictionary());
/// <summary>
/// The default path for cached folders on the server.
/// </summary>
private static readonly string CachePath = ImageProcessorConfig.Instance.VirtualCachePath;
/// <summary>
/// The object to lock against.
/// </summary>
private static readonly object SyncRoot = new object();
/// <summary>
/// The cached index location.
/// </summary>
private readonly string cachedIndexFile = Path.Combine(HostingEnvironment.MapPath(CachePath), "imagecache.bin");
#endregion
#region Constructors
/// <summary>
@ -92,7 +82,7 @@ namespace ImageProcessor.Web.Caching
value = this[key];
this.Remove(key);
this.SaveCache();
this.SaveCache(key, value, true);
return true;
}
@ -104,29 +94,23 @@ namespace ImageProcessor.Web.Caching
/// <param name="key">
/// The key.
/// </param>
/// <param name="factory">
/// The delegate method that returns the value.
/// <param name="cachedImage">
/// The cached image to add.
/// </param>
/// <returns>
/// The value of the item to add or get.
/// </returns>
public CachedImage GetOrAdd(string key, Func<string, CachedImage> factory)
public new CachedImage Add(string key, CachedImage cachedImage)
{
// Get the CachedImage.
if (this.ContainsKey(key))
{
return this[key];
}
lock (SyncRoot)
{
// Add the CachedImage.
CachedImage ret = factory(key);
this[key] = ret;
this.SaveCache();
if (this.SaveCache(key, cachedImage, false))
{
this[key] = cachedImage;
}
return ret;
return cachedImage;
}
}
#endregion
@ -134,22 +118,32 @@ namespace ImageProcessor.Web.Caching
/// <summary>
/// Saves the in memory cache to the file-system.
/// </summary>
private void SaveCache()
/// <param name="key">
/// The key.
/// </param>
/// <param name="cachedImage">
/// The cached Image.
/// </param>
/// <param name="remove">
/// The remove.
/// </param>
/// <returns>
/// true, if the dictionary is saved to the file-system; otherwise, false.
/// </returns>
private bool SaveCache(string key, CachedImage cachedImage, bool remove)
{
using (FileStream fileStream = File.Create(this.cachedIndexFile))
try
{
using (BinaryWriter binaryWriter = new BinaryWriter(fileStream))
if (remove)
{
// Put the count.
binaryWriter.Write(this.Count);
// Put the values.
foreach (var pair in this)
{
binaryWriter.Write(pair.Key);
binaryWriter.Write(pair.Value.ValueAndLastWriteTimeUtcToString());
}
return SQLContext.RemoveImage(key);
}
return SQLContext.AddImage(key, cachedImage);
}
catch (Exception)
{
return false;
}
}
@ -160,32 +154,13 @@ namespace ImageProcessor.Web.Caching
{
lock (SyncRoot)
{
if (File.Exists(this.cachedIndexFile))
SQLContext.CreateDatabase();
Dictionary<string, CachedImage> dictionary = SQLContext.GetImages();
foreach (KeyValuePair<string, CachedImage> pair in dictionary)
{
using (FileStream fileStream = File.OpenRead(this.cachedIndexFile))
{
using (BinaryReader binaryReader = new BinaryReader(fileStream))
{
// Get the count.
int count = binaryReader.ReadInt32();
// Read in all pairs.
for (int i = 0; i < count; i++)
{
// Read the key/value strings
string key = binaryReader.ReadString();
string value = binaryReader.ReadString();
// Create a CachedImage
string[] valueAndLastWriteTime = value.Split(new[] { CachedImage.ValueLastWriteTimeDelimiter }, StringSplitOptions.None);
DateTime lastWriteTime = DateTime.Parse(valueAndLastWriteTime[1]);
CachedImage cachedImage = new CachedImage(valueAndLastWriteTime[0], lastWriteTime);
// Assign the value
this[key] = cachedImage;
}
}
}
this.Add(pair);
}
}
}

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

@ -0,0 +1,216 @@
// -----------------------------------------------------------------------
// <copyright file="SQLContext.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.Data.SQLite;
using System.IO;
using System.Web.Hosting;
using ImageProcessor.Web.Config;
#endregion
/// <summary>
/// Provides a wrapper for the SQLite functionality.
/// </summary>
internal sealed class SQLContext
{
/// <summary>
/// The default path for cached folders on the server.
/// </summary>
private static readonly string VirtualCachePath = ImageProcessorConfig.Instance.VirtualCachePath;
/// <summary>
/// The cached index location.
/// </summary>
private static readonly string IndexLocation = Path.Combine(HostingEnvironment.MapPath(VirtualCachePath), "imagecache.sqlite");
/// <summary>
/// The connection string.
/// </summary>
private static readonly string ConnectionString = string.Format("Data Source={0};Version=3;", IndexLocation);
/// <summary>
/// Creates the database if it doesn't already exist.
/// </summary>
public static void CreateDatabase()
{
if (!File.Exists(IndexLocation))
{
string absolutePath = HostingEnvironment.MapPath(VirtualCachePath);
if (absolutePath != null)
{
DirectoryInfo directoryInfo = new DirectoryInfo(absolutePath);
if (!directoryInfo.Exists)
{
// Create the directory.
Directory.CreateDirectory(absolutePath);
}
}
SQLiteConnection.CreateFile(IndexLocation);
using (SQLiteConnection connection = new SQLiteConnection(ConnectionString))
{
connection.Open();
using (SQLiteTransaction transaction = connection.BeginTransaction())
{
using (SQLiteCommand command = new SQLiteCommand(connection))
{
command.CommandText = @"CREATE TABLE names
(Key TEXT,
Path TEXT,
LastWriteTimeUtc TEXT,
ExpiresUtc TEXT,
PRIMARY KEY (Key),
UNIQUE (Value));";
command.ExecuteNonQuery();
}
transaction.Commit();
}
}
}
}
/// <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>
public static bool AddImage(string key, CachedImage image)
{
try
{
using (SQLiteConnection connection = new SQLiteConnection(ConnectionString))
{
connection.Open();
using (SQLiteTransaction transaction = connection.BeginTransaction())
{
using (SQLiteCommand command = new SQLiteCommand(connection))
{
command.CommandText = "INSERT INTO names VALUES(?, ?, ?, ?)";
SQLiteParameter[] parameters = new[]
{
new SQLiteParameter("Key", key),
new SQLiteParameter("Path", image.Path),
new SQLiteParameter("LastWriteTimeUtc", image.LastWriteTimeUtc),
new SQLiteParameter("ExpiresUtc", image.ExpiresUtc)
};
command.Parameters.AddRange(parameters);
command.ExecuteNonQuery();
}
transaction.Commit();
}
}
return true;
}
catch (Exception)
{
return false;
}
}
/// <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>
public static bool RemoveImage(string key)
{
try
{
using (SQLiteConnection connection = new SQLiteConnection(ConnectionString))
{
connection.Open();
using (SQLiteTransaction transaction = connection.BeginTransaction())
{
using (SQLiteCommand command = new SQLiteCommand(connection))
{
command.CommandText = string.Format("DELETE FROM names WHERE key = '{0}';", key);
command.ExecuteNonQuery();
}
transaction.Commit();
}
}
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// 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(),
DateTime.Parse(reader["LastWriteTimeUtc"].ToString()).ToUniversalTime(),
DateTime.Parse(reader["LastWriteTimeUtc"].ToString()).ToUniversalTime());
dictionary.Add(key, image);
}
}
}
return dictionary;
}
catch (Exception)
{
return new Dictionary<string, CachedImage>();
}
}
}
}

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

@ -27,14 +27,14 @@ namespace ImageProcessor.Web.HttpModules
{
#region Fields
/// <summary>
/// The value to prefix any remote image requests with to ensure they get captured.
/// The key for storing the response type of the current image.
/// </summary>
private static readonly string RemotePrefix = ImageProcessorConfig.Instance.RemotePrefix;
private const string CachedResponseTypeKey = "CACHED_IMAGE_RESPONSE_TYPE";
/// <summary>
/// The key for storing the response type of the current image.
/// The value to prefix any remote image requests with to ensure they get captured.
/// </summary>
private const string CachedResponseTypeKey = "CACHED_IMAGE_RESPONSE_TYPE";
private static readonly string RemotePrefix = ImageProcessorConfig.Instance.RemotePrefix;
/// <summary>
/// Whether this is the first run of the handler.
@ -153,16 +153,7 @@ namespace ImageProcessor.Web.HttpModules
}
else
{
try
{
imageFactory.Load(fullPath).AutoProcess().Save(cachedPath);
}
catch (Exception ex)
{
throw ex;
}
imageFactory.Load(fullPath).AutoProcess().Save(cachedPath);
}
}
@ -170,7 +161,10 @@ namespace ImageProcessor.Web.HttpModules
cachedImageCounter += 1;
// Ensure that the LastWriteTime property of the source and cached file match.
DiskCache.SetCachedLastWriteTime(path, cachedPath);
DateTime dateTime = DiskCache.SetCachedLastWriteTime(path, cachedPath);
// Add to the cache.
DiskCache.AddImageToCache(cachedPath, dateTime);
}
context.Items[CachedResponseTypeKey] = ImageUtils.GetResponseType(imageName).ToDescription();
@ -180,7 +174,7 @@ namespace ImageProcessor.Web.HttpModules
// If the number of cached imaged hits the maximum allowed for this session then we clear
// the cache again and reset the counter.
// TODO: There is a potential concurrency issue here but collision probability is very low#
// TODO: There is a potential concurrency issue here but collision probability is very low
// it would be nice to nail it though.
if (cachedImageCounter >= DiskCache.MaxRunsBeforeCacheClear)
{
@ -192,7 +186,7 @@ namespace ImageProcessor.Web.HttpModules
}
/// <summary>
/// Occurs just before ASP.NET send Httpheaders to the client.
/// 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>

40
src/ImageProcessor.Web/ImageProcessor.Web.csproj

@ -38,10 +38,45 @@
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'All|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\All\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Data.SQLite, Version=1.0.84.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\System.Data.SQLite.x86.1.0.84.0\lib\net40\System.Data.SQLite.dll</HintPath>
</Reference>
<Reference Include="System.Data.SQLite.Linq, Version=1.0.84.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\System.Data.SQLite.x86.1.0.84.0\lib\net40\System.Data.SQLite.Linq.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
@ -55,6 +90,7 @@
<Compile Include="Caching\DiskCache.cs" />
<Compile Include="Caching\LockedDictionary.cs" />
<Compile Include="Caching\PersistantDictionary.cs" />
<Compile Include="Caching\SQLContext.cs" />
<Compile Include="Config\ImageCacheSection.cs" />
<Compile Include="Config\ImageProcessingSection.cs" />
<Compile Include="Config\ImageProcessorConfig.cs" />
@ -71,7 +107,9 @@
<Name>ImageProcessor</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- 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.

4
src/ImageProcessor.Web/packages.config

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="System.Data.SQLite.x86" version="1.0.84.0" targetFramework="net40" />
</packages>

37
src/ImageProcessor.sln

@ -1,37 +1,72 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2012 for Web
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor", "ImageProcessor\ImageProcessor.csproj", "{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test\Test.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web", "ImageProcessor.Web\ImageProcessor.Web.csproj", "{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Tests", "ImageProcessor.Tests\ImageProcessor.Tests.csproj", "{39911A38-CA06-413C-80AA-39EF60CE984F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
All|Any CPU = All|Any CPU
All|x86 = All|x86
Debug|Any CPU = Debug|Any CPU
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|x86.ActiveCfg = All|x86
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|x86.Build.0 = All|x86
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.Build.0 = Release|Any CPU
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|x86.ActiveCfg = Debug|x86
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|x86.Build.0 = Debug|x86
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.Build.0 = Release|Any CPU
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|x86.ActiveCfg = Release|x86
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|x86.Build.0 = Release|x86
{30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.ActiveCfg = All|Any CPU
{30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.Build.0 = All|Any CPU
{30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.ActiveCfg = All|x86
{30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.Build.0 = All|x86
{30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.Build.0 = Debug|Any CPU
{30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.ActiveCfg = Debug|x86
{30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.Build.0 = Debug|x86
{30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.ActiveCfg = Release|Any CPU
{30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.Build.0 = Release|Any CPU
{30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.ActiveCfg = Release|x86
{30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.Build.0 = Release|x86
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.ActiveCfg = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.Build.0 = All|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|x86.ActiveCfg = All|x86
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|x86.Build.0 = All|x86
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.Build.0 = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|x86.ActiveCfg = Debug|x86
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|x86.Build.0 = Debug|x86
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.Build.0 = Release|Any CPU
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|x86.ActiveCfg = Release|x86
{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|x86.Build.0 = Release|x86
{39911A38-CA06-413C-80AA-39EF60CE984F}.All|Any CPU.ActiveCfg = Release|Any CPU
{39911A38-CA06-413C-80AA-39EF60CE984F}.All|Any CPU.Build.0 = Release|Any CPU
{39911A38-CA06-413C-80AA-39EF60CE984F}.All|x86.ActiveCfg = Release|x86
{39911A38-CA06-413C-80AA-39EF60CE984F}.All|x86.Build.0 = Release|x86
{39911A38-CA06-413C-80AA-39EF60CE984F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39911A38-CA06-413C-80AA-39EF60CE984F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39911A38-CA06-413C-80AA-39EF60CE984F}.Debug|x86.ActiveCfg = Debug|x86
{39911A38-CA06-413C-80AA-39EF60CE984F}.Debug|x86.Build.0 = Debug|x86
{39911A38-CA06-413C-80AA-39EF60CE984F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39911A38-CA06-413C-80AA-39EF60CE984F}.Release|Any CPU.Build.0 = Release|Any CPU
{39911A38-CA06-413C-80AA-39EF60CE984F}.Release|x86.ActiveCfg = Release|x86
{39911A38-CA06-413C-80AA-39EF60CE984F}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

31
src/ImageProcessor/ImageProcessor.csproj

@ -44,6 +44,37 @@
<CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\ImageProcessor.XML</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<DocumentationFile>bin\Release\ImageProcessor.XML</DocumentationFile>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'All|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\All\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\ImageProcessor.XML</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Configuration" />

32
src/Test/Test/Controllers/HomeController.cs

@ -10,6 +10,8 @@ namespace Test.Controllers
using System.Threading.Tasks;
using System.Web.Hosting;
using ImageProcessor.Web.Caching;
public class HomeController : Controller
{
public ActionResult Index()
@ -47,7 +49,37 @@ namespace Test.Controllers
public ActionResult Responsive()
{
return this.View();
}
public ActionResult Speed()
{
DateTime start = DateTime.Now;
//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;
//ViewBag.Count = persistantDictionary.Count();
return this.View(timeSpan);
}
}
}

30
src/Test/Test/Test.csproj

@ -131,10 +131,40 @@
<ItemGroup>
<Content Include="Views\Home\Responsive.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Home\Speed.cshtml" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'All|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />

20
src/Test/Test/Views/Home/Speed.cshtml

@ -0,0 +1,20 @@
@model TimeSpan
@{
Layout = null;
double s = Model.TotalMilliseconds;
}
<!DOCTYPE html>
<html>
<head>
<title>@s</title>
</head>
<body>
<div>
Speed In Milliseconds: @s<br/>
Dictionary Count: @ViewBag.Count
</div>
</body>
</html>

2
src/Test/Test/Web.config

@ -21,7 +21,7 @@
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.0">
<compilation debug="false" targetFramework="4.0">
<assemblies>
<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" />

1
src/packages/System.Data.SQLite.x86.1.0.84.0/System.Data.SQLite.x86.1.0.84.0.nupkg.REMOVED.git-id

@ -0,0 +1 @@
2db1579b36b2d81adf041533845e9a72ea6c2393

23
src/packages/System.Data.SQLite.x86.1.0.84.0/System.Data.SQLite.x86.1.0.84.0.nuspec

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>System.Data.SQLite.x86</id>
<version>1.0.84.0</version>
<title>System.Data.SQLite.x86</title>
<authors>SQLite Development Team</authors>
<owners>SQLite Development Team</owners>
<licenseUrl>http://www.sqlite.org/copyright.html</licenseUrl>
<projectUrl>http://system.data.sqlite.org/</projectUrl>
<iconUrl>http://system.data.sqlite.org/images/sqlite32.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>The official SQLite database engine combined with a complete ADO.NET provider all rolled into a single mixed-mode assembly for x86.</description>
<releaseNotes />
<copyright>Public Domain</copyright>
<language>en-US</language>
<tags>sqlite database ado.net provider interop</tags>
<references>
<reference file="System.Data.SQLite.dll" />
<reference file="System.Data.SQLite.Linq.dll" />
</references>
</metadata>
</package>

1
src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net20/System.Data.SQLite.Linq.dll.REMOVED.git-id

@ -0,0 +1 @@
91d583cc0540c5252c68278bea13a48045548a20

1
src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net20/System.Data.SQLite.dll.REMOVED.git-id

@ -0,0 +1 @@
168e4329b21098e36b1c1af6e0c8728d5e9c589e

1
src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net40/System.Data.SQLite.Linq.dll.REMOVED.git-id

@ -0,0 +1 @@
31c463596b575043d8559b8a10cb25ad3bc15090

1
src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net40/System.Data.SQLite.dll.REMOVED.git-id

@ -0,0 +1 @@
f60b588d3ff22ae8b1f51d710a44a037683ce81d

1
src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net45/System.Data.SQLite.Linq.dll.REMOVED.git-id

@ -0,0 +1 @@
71a4551ce7011a6caeeadb73aea687ec586a5d87

1
src/packages/System.Data.SQLite.x86.1.0.84.0/lib/net45/System.Data.SQLite.dll.REMOVED.git-id

@ -0,0 +1 @@
c62d000052745e37933833a3b764eb47ece9673f

4
src/packages/repositories.config

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<repositories>
<repository path="..\ImageProcessor.Web\packages.config" />
</repositories>
Loading…
Cancel
Save