├── .gitignore ├── Asp.Net.Example ├── ApplicationBootrapper.cs ├── Asp.Net.Example.csproj ├── Asp.Net.Example.csproj.user ├── ExampleModule.cs ├── Module.cs ├── Properties │ └── AssemblyInfo.cs ├── Views │ ├── TestView.html │ └── hello.html ├── Web.Debug.config ├── Web.Release.config ├── Web.config └── packages.config ├── Nancy.LightningCache.sln ├── Nancy.LightningCache ├── CacheKey │ ├── DefaultCacheKeyGenerator.cs │ └── ICacheKeyGenerator.cs ├── CacheStore │ ├── DiskCacheStore.cs │ ├── ICacheStore.cs │ └── WebCacheStore.cs ├── Extensions │ ├── NancyBootstrapperExtensions.cs │ ├── NegotiatorExtensions.cs │ └── ResponseExtensions.cs ├── LightningCache.cs ├── Nancy.LightningCache.csproj ├── Nancy.LightningCache.csproj.nuspec ├── Projection │ ├── CacheableResponse.cs │ ├── CachedResponse.cs │ └── SerializableResponse.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── README.md ├── build.bat ├── build.boo ├── packages └── repositories.config └── tools ├── NuGet.exe ├── Phantom ├── Boo.Lang.Compiler.dll ├── Boo.Lang.Parser.dll ├── Boo.Lang.dll ├── EasyHttp.dll ├── EasyHttp.pdb ├── Ionic.Zip.dll ├── Microsoft.Web.Administration.dll ├── Newtonsoft.Json.dll ├── Newtonsoft.Json.xml ├── Phantom.Core.dll ├── Phantom.Core.pdb ├── Phantom.DSL.Boo.dll ├── Phantom.DSL.Boo.pdb ├── Phantom.exe ├── Phantom.exe.config ├── Phantom.pdb ├── Phantom.vshost.exe ├── Phantom.vshost.exe.config ├── Phantom.vshost.exe.manifest ├── PhantomContrib.dll ├── PhantomContrib.pdb ├── Rhino.DSL.dll ├── Tipser.Executionr.dll ├── Tipser.Executionr.pdb ├── Tipser.Versionator.dll └── Tipser.Versionator.pdb └── UpdateVersion.exe /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | bin 3 | obj 4 | 5 | #resharper 6 | _ReSharper.Nancy.LightningCache 7 | 8 | #other 9 | Nancy.LightningCache.v11.suo 10 | 11 | # mstest test results 12 | TestResults -------------------------------------------------------------------------------- /Asp.Net.Example/ApplicationBootrapper.cs: -------------------------------------------------------------------------------- 1 | using Nancy.LightningCache.CacheKey; 2 | using Nancy.LightningCache.CacheStore; 3 | using Nancy.LightningCache.Extensions; 4 | using Nancy.Routing; 5 | 6 | namespace Asp.Net.Example 7 | { 8 | public class ApplicationBootrapper : Nancy.DefaultNancyBootstrapper 9 | { 10 | protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines) 11 | { 12 | base.ApplicationStartup(container, pipelines); 13 | 14 | /*enable lightningcache, vary by url params id,query,take and skip*/ 15 | this.EnableLightningCache(container.Resolve(), ApplicationPipelines, new DefaultCacheKeyGenerator(new[] { "id", "query", "take", "skip" })); 16 | /*enable lightningcache using the DiskCacheStore, vary by url params id,query,take and skip*/ 17 | //this.EnableLightningCache(container.Resolve(), ApplicationPipelines, new DefaultCacheKeyGenerator(new[] { "id", "query", "take", "skip" }), new DiskCacheStore("c:/tmp/cache")); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Asp.Net.Example/Asp.Net.Example.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | 2.0 10 | {9B3CABB5-4AD2-4AA0-8B41-E293CCD9563E} 11 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 12 | Library 13 | Properties 14 | Asp.Net.Example 15 | Asp.Net.Example 16 | v4.0 17 | true 18 | 19 | 20 | 21 | 22 | 23 | 24 | true 25 | full 26 | false 27 | bin\ 28 | DEBUG;TRACE 29 | prompt 30 | 4 31 | 32 | 33 | pdbonly 34 | true 35 | bin\ 36 | TRACE 37 | prompt 38 | 4 39 | 40 | 41 | 42 | 43 | False 44 | ..\packages\Nancy.0.23.2\lib\net40\Nancy.dll 45 | 46 | 47 | False 48 | ..\packages\Nancy.Authentication.Forms.0.23.2\lib\net40\Nancy.Authentication.Forms.dll 49 | 50 | 51 | False 52 | ..\packages\Nancy.Hosting.Aspnet.0.23.2\lib\net40\Nancy.Hosting.Aspnet.dll 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | Web.config 84 | 85 | 86 | Web.config 87 | 88 | 89 | 90 | 91 | {fde0905b-f713-478c-83bc-9872631758fe} 92 | Nancy.LightningCache 93 | 94 | 95 | 96 | 10.0 97 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | True 107 | True 108 | 0 109 | / 110 | http://localhost:53057/ 111 | False 112 | False 113 | 114 | 115 | False 116 | 117 | 118 | 119 | 120 | 127 | -------------------------------------------------------------------------------- /Asp.Net.Example/Asp.Net.Example.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | CurrentPage 10 | True 11 | False 12 | False 13 | False 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | False 23 | True 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Asp.Net.Example/ExampleModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Nancy; 3 | using Nancy.LightningCache.Extensions; 4 | 5 | namespace Asp.Net.Example 6 | { 7 | public class ExampleModule : NancyModule 8 | { 9 | public ExampleModule() 10 | { 11 | Get["/"] = _ => 12 | { 13 | /*cache view*/ 14 | return View["hello.html"].AsCacheable(DateTime.Now.AddSeconds(30)); 15 | }; 16 | 17 | Get["/CachedResponse"] = _ => 18 | { 19 | /*cache response*/ 20 | return Response.AsText("hello").AsCacheable(DateTime.Now.AddSeconds(30)); 21 | }; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Asp.Net.Example/Module.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Nancy; 4 | using Nancy.LightningCache.Extensions; 5 | 6 | namespace Asp.Net.Example 7 | { 8 | public class Module : NancyModule 9 | { 10 | public Module() 11 | { 12 | Get["/"] = _ => 13 | { 14 | return View["TestView.html", new { Hello = DateTime.Now.ToString(CultureInfo.InvariantCulture)}].AsCacheable(DateTime.Now.AddSeconds(1)); 15 | }; 16 | 17 | Get["/CachedResponse"] = _ => 18 | { 19 | return Response.AsText(@" 20 | this is a cached response: "+DateTime.Now.ToString(CultureInfo.InvariantCulture)+@" 21 | ").AsCacheable(DateTime.Now.AddSeconds(1)); 22 | }; 23 | 24 | 25 | Get["/faultyResponse"] = _ => 26 | { 27 | return new Response() {StatusCode = HttpStatusCode.InternalServerError}.AsCacheable(DateTime.Now.AddSeconds(30)); 28 | }; 29 | 30 | Get["/faultyConditionalResponse"] = _ => 31 | { 32 | return new Response() { StatusCode = (string)Request.Query.fault.Value == "true" ? HttpStatusCode.InternalServerError : HttpStatusCode.OK }.AsCacheable(DateTime.Now.AddSeconds(1)); 33 | }; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Asp.Net.Example/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Asp.Net.Example")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Asp.Net.Example")] 13 | [assembly: AssemblyCopyright("Copyright © 2012")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c37aaa48-ee6d-458f-adbc-deda1d31a46f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Asp.Net.Example/Views/TestView.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 |

hello!

8 | 9 |

this is a cached view: @!Model.Hello

10 | 11 | click here for a cached response 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Asp.Net.Example/Views/hello.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 |

hello!

8 | 9 |

this is a cached view: @!Model.Hello

10 | 11 | click here for a cached response 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Asp.Net.Example/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /Asp.Net.Example/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /Asp.Net.Example/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Asp.Net.Example/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Nancy.LightningCache.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nancy.LightningCache", "Nancy.LightningCache\Nancy.LightningCache.csproj", "{FDE0905B-F713-478C-83BC-9872631758FE}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Asp.Net.Example", "Asp.Net.Example\Asp.Net.Example.csproj", "{9B3CABB5-4AD2-4AA0-8B41-E293CCD9563E}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {FDE0905B-F713-478C-83BC-9872631758FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {FDE0905B-F713-478C-83BC-9872631758FE}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {FDE0905B-F713-478C-83BC-9872631758FE}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {FDE0905B-F713-478C-83BC-9872631758FE}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {9B3CABB5-4AD2-4AA0-8B41-E293CCD9563E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {9B3CABB5-4AD2-4AA0-8B41-E293CCD9563E}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {9B3CABB5-4AD2-4AA0-8B41-E293CCD9563E}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {9B3CABB5-4AD2-4AA0-8B41-E293CCD9563E}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /Nancy.LightningCache/CacheKey/DefaultCacheKeyGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Nancy.LightningCache.CacheKey 6 | { 7 | public class DefaultCacheKeyGenerator : ICacheKeyGenerator 8 | { 9 | private static string[] _varyParams = new string[0]; 10 | 11 | public DefaultCacheKeyGenerator(string[] varyParams) 12 | { 13 | _varyParams = varyParams; 14 | } 15 | 16 | /// 17 | /// Generates a cache key from the supplied Request 18 | /// 19 | /// 20 | /// 21 | public string Get(Request request) 22 | { 23 | if (request == null || request.Url == null) 24 | return string.Empty; 25 | 26 | var query = new Dictionary(); 27 | 28 | if (request.Query is DynamicDictionary) 29 | { 30 | var dynDict = (request.Query as DynamicDictionary); 31 | foreach (var key in dynDict.Keys) 32 | { 33 | query[key] = (string)dynDict[key]; 34 | } 35 | } 36 | 37 | if (request.Form is DynamicDictionary) 38 | { 39 | var dynDict = (request.Form as DynamicDictionary); 40 | foreach (var key in dynDict.Keys) 41 | { 42 | query[key] = (string)dynDict[key]; 43 | } 44 | } 45 | 46 | var removeParamKeys = query.Where(a => !_varyParams.Contains(a.Key.Replace("?", "").ToLower())).Select(a => a.Key).ToArray(); 47 | foreach (var removeParamKey in removeParamKeys) 48 | query.Remove(removeParamKey); 49 | 50 | var url = new Url 51 | { 52 | BasePath = request.Url.BasePath, 53 | HostName = request.Url.HostName, 54 | Path = request.Url.Path, 55 | Port = request.Url.Port, 56 | Query = (query.Count > 0 ? "?" : string.Empty) + string.Join("&", query.Select(a => string.Join("=", a.Key, a.Value))), 57 | Scheme = request.Url.Scheme, 58 | }; 59 | 60 | return url.ToString(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Nancy.LightningCache/CacheKey/ICacheKeyGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Nancy.LightningCache.CacheKey 4 | { 5 | /// 6 | /// CacheKeyGenerator meant to be consumed by Nancy.LightningCache 7 | /// 8 | public interface ICacheKeyGenerator 9 | { 10 | string Get(Request request); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Nancy.LightningCache/CacheStore/DiskCacheStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Security.Cryptography; 6 | using System.Text; 7 | using Nancy.Json; 8 | using Nancy.LightningCache.Projection; 9 | 10 | namespace Nancy.LightningCache.CacheStore 11 | { 12 | /// 13 | /// Stores Responses serialized as JSON. 14 | /// File names are SHA256 hashes of the supplied key with each response sent to this cache store. 15 | /// 16 | public class DiskCacheStore : ICacheStore 17 | { 18 | private readonly string _cacheDirectory = string.Empty; 19 | private readonly JavaScriptSerializer _javaScriptSerializer; 20 | private readonly object _lock = new object(); 21 | private static readonly Dictionary FileKeyExpirationRecord = new Dictionary(); 22 | private static TimeSpan _expiredFilesDeletionOffset; 23 | 24 | 25 | /// 26 | /// 27 | /// 28 | /// absolute path to directory where to store cached files 29 | /// extra time to keep expired files before deleting them 30 | public DiskCacheStore(string cacheDirectory, TimeSpan expiredFilesDeletionOffset) 31 | { 32 | if (!Path.IsPathRooted(cacheDirectory)) 33 | throw new ArgumentException("cache directory must contain a root, it must be an absolute path", "cacheDirectory"); 34 | 35 | if (!Directory.Exists(cacheDirectory)) 36 | Directory.CreateDirectory(cacheDirectory); 37 | 38 | File.WriteAllText(Path.Combine(cacheDirectory, GetType().FullName), GetType().FullName); 39 | File.Delete(Path.Combine(cacheDirectory, GetType().FullName)); 40 | 41 | _cacheDirectory = cacheDirectory; 42 | _javaScriptSerializer = new JavaScriptSerializer(); 43 | 44 | _expiredFilesDeletionOffset = expiredFilesDeletionOffset; 45 | } 46 | 47 | /// 48 | /// 49 | /// 50 | /// absolute path to directory where to store cached files 51 | public DiskCacheStore(string cacheDirectory) 52 | { 53 | if (!Path.IsPathRooted(cacheDirectory)) 54 | throw new ArgumentException("cache directory must contain a root, it must be an absolute path", "cacheDirectory"); 55 | 56 | if (!Directory.Exists(cacheDirectory)) 57 | Directory.CreateDirectory(cacheDirectory); 58 | 59 | File.WriteAllText(Path.Combine(cacheDirectory, GetType().FullName), GetType().FullName); 60 | File.Delete(Path.Combine(cacheDirectory, GetType().FullName)); 61 | 62 | _cacheDirectory = cacheDirectory; 63 | _javaScriptSerializer = new JavaScriptSerializer(); 64 | 65 | _expiredFilesDeletionOffset = new TimeSpan(0,0,24,0); 66 | } 67 | 68 | /// 69 | /// 70 | /// 71 | /// 72 | /// 73 | private static string Hash(string str) 74 | { 75 | var hasher = SHA256.Create(); 76 | var inputBytes = Encoding.ASCII.GetBytes(str); 77 | var hashBytes = hasher.ComputeHash(inputBytes); 78 | 79 | var sb = new StringBuilder(); 80 | 81 | for (var i = 0; i < hashBytes.Length; i++) 82 | sb.Append(hashBytes[i].ToString("x2")); 83 | 84 | return sb.ToString(); 85 | } 86 | 87 | /// 88 | /// 89 | /// 90 | private void DeleteExpiredCacheFiles() 91 | { 92 | var files = FileKeyExpirationRecord 93 | .Where(record => DateTime.Now >= record.Value.Add(_expiredFilesDeletionOffset)) 94 | .Select(record => record.Key) 95 | .ToArray(); 96 | foreach (var file in files) 97 | { 98 | if(File.Exists(Path.Combine(_cacheDirectory, file))) 99 | { 100 | File.Delete(Path.Combine(_cacheDirectory, file)); 101 | } 102 | FileKeyExpirationRecord.Remove(file); 103 | } 104 | } 105 | 106 | /// 107 | /// 108 | /// 109 | /// 110 | /// 111 | public CachedResponse Get(string key) 112 | { 113 | lock(_lock) 114 | { 115 | var fileName = Hash(key); 116 | if (File.Exists(Path.Combine(_cacheDirectory, fileName))) 117 | { 118 | var json = File.ReadAllText(Path.Combine(_cacheDirectory, fileName)); 119 | var serializedResponse = _javaScriptSerializer.Deserialize(json); 120 | return new CachedResponse(serializedResponse); 121 | } 122 | } 123 | return null; 124 | } 125 | 126 | /// 127 | /// 128 | /// 129 | /// 130 | public void Remove(string key) 131 | { 132 | lock(_lock) 133 | { 134 | var fileName = Hash(key); 135 | if(File.Exists(Path.Combine(_cacheDirectory, fileName))) 136 | File.Delete(Path.Combine(_cacheDirectory, fileName)); 137 | if (FileKeyExpirationRecord.ContainsKey(fileName)) 138 | FileKeyExpirationRecord.Remove(fileName); 139 | } 140 | } 141 | 142 | /// 143 | /// 144 | /// 145 | /// 146 | /// 147 | /// 148 | public void Set(string key, NancyContext context, DateTime absoluteExpiration) 149 | { 150 | lock (_lock) 151 | { 152 | 153 | var fileName = Hash(key); 154 | if (File.Exists(Path.Combine(_cacheDirectory, fileName))) 155 | File.Delete(Path.Combine(_cacheDirectory, fileName)); 156 | var serializedResponse = new SerializableResponse(context.Response, absoluteExpiration); 157 | var json = _javaScriptSerializer.Serialize(serializedResponse); 158 | File.WriteAllText(Path.Combine(_cacheDirectory, fileName), json); 159 | 160 | DeleteExpiredCacheFiles(); 161 | FileKeyExpirationRecord[fileName] = absoluteExpiration; 162 | } 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /Nancy.LightningCache/CacheStore/ICacheStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Nancy.LightningCache.Projection; 3 | 4 | namespace Nancy.LightningCache.CacheStore 5 | { 6 | /// 7 | /// CacheStore meant to be consumed by Nancy.LightningCache 8 | /// 9 | public interface ICacheStore 10 | { 11 | CachedResponse Get(string key); 12 | void Set(string key, NancyContext context, DateTime absoluteExpiration); 13 | void Remove(string key); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Nancy.LightningCache/CacheStore/WebCacheStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web; 3 | using System.Web.Caching; 4 | using Nancy.LightningCache.Projection; 5 | 6 | namespace Nancy.LightningCache.CacheStore 7 | { 8 | /// 9 | /// CacheStore that stores content using the System.Web.Cache 10 | /// 11 | public class WebCacheStore : ICacheStore 12 | { 13 | private Cache _cache; 14 | 15 | public CachedResponse Get(string key) 16 | { 17 | SetCache(); 18 | 19 | if (_cache == null) 20 | return null; 21 | 22 | var response = _cache.Get(key) as SerializableResponse; 23 | 24 | if (response == null) 25 | return null; 26 | 27 | return new CachedResponse(response); 28 | } 29 | 30 | public void Remove(string key) 31 | { 32 | SetCache(); 33 | 34 | if (_cache == null) 35 | return; 36 | 37 | _cache.Remove(key); 38 | } 39 | 40 | public void Set(string key, NancyContext context, DateTime absoluteExpiration) 41 | { 42 | SetCache(); 43 | 44 | if(_cache == null) 45 | return; 46 | 47 | _cache[key] = new SerializableResponse(context.Response, absoluteExpiration); 48 | 49 | } 50 | private static readonly object Lock = new object(); 51 | private void SetCache() 52 | { 53 | lock(Lock) 54 | { 55 | if (HttpContext.Current == null || _cache != null) 56 | return; 57 | _cache = HttpContext.Current.Cache; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Nancy.LightningCache/Extensions/NancyBootstrapperExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Nancy.Bootstrapper; 4 | using Nancy.LightningCache.CacheKey; 5 | using Nancy.LightningCache.CacheStore; 6 | using Nancy.Routing; 7 | 8 | namespace Nancy.LightningCache.Extensions 9 | { 10 | public static class NancyBootstrapperExtensions 11 | { 12 | /// 13 | /// Enables Nancy.LightningCache using the supplied parameters 14 | /// 15 | /// 16 | /// 17 | /// 18 | /// 19 | public static void EnableLightningCache(this INancyBootstrapper bootstrapper, IRouteResolver routeResolver, IPipelines pipelines, string[] varyParams) 20 | { 21 | LightningCache.Enable(bootstrapper, routeResolver, pipelines, varyParams); 22 | } 23 | 24 | /// 25 | /// Enables Nancy.LightningCache using the supplied parameters and CacheStore type 26 | /// 27 | /// 28 | /// 29 | /// 30 | /// 31 | /// 32 | public static void EnableLightningCache(this INancyBootstrapper bootstrapper, IRouteResolver routeResolver, IPipelines pipelines, string[] varyParams, ICacheStore cacheStore) 33 | { 34 | LightningCache.Enable(bootstrapper, routeResolver, pipelines, new DefaultCacheKeyGenerator(varyParams), cacheStore); 35 | } 36 | 37 | /// 38 | /// Enables Nancy.LightningCache using the supplied parameters 39 | /// 40 | /// 41 | /// 42 | /// 43 | /// 44 | public static void EnableLightningCache(this INancyBootstrapper bootstrapper, IRouteResolver routeResolver, IPipelines pipelines, ICacheKeyGenerator cacheKeyGenerator) 45 | { 46 | LightningCache.Enable(bootstrapper, routeResolver, pipelines, cacheKeyGenerator); 47 | } 48 | 49 | /// 50 | /// Enables Nancy.LightningCache using the supplied parameters and CacheStore type 51 | /// 52 | /// 53 | /// 54 | /// 55 | /// 56 | /// 57 | public static void EnableLightningCache(this INancyBootstrapper bootstrapper, IRouteResolver routeResolver, IPipelines pipelines, ICacheKeyGenerator cacheKeyGenerator, ICacheStore cacheStore) 58 | { 59 | LightningCache.Enable(bootstrapper, routeResolver, pipelines, cacheKeyGenerator, cacheStore); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Nancy.LightningCache/Extensions/NegotiatorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Nancy.Responses.Negotiation; 4 | 5 | namespace Nancy.LightningCache.Extensions 6 | { 7 | public static class NegotiatorExtensions 8 | { 9 | /// 10 | /// Extensions method used to mark this Negotiator as cacheable by Nancy.LightningCache 11 | /// 12 | /// 13 | /// 14 | /// 15 | public static Negotiator AsCacheable(this Negotiator negotiator, DateTime expiration) 16 | { 17 | return negotiator.WithHeader("nancy-lightningcache", expiration.ToString(CultureInfo.InvariantCulture)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Nancy.LightningCache/Extensions/ResponseExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Nancy.LightningCache.Projection; 3 | 4 | namespace Nancy.LightningCache.Extensions 5 | { 6 | public static class ResponseExtensions 7 | { 8 | 9 | /// 10 | /// Extension method used to mark this response as cacheable by Nancy.LightningCache 11 | /// 12 | /// 13 | /// 14 | /// 15 | public static Response AsCacheable(this Response response, DateTime expiration) 16 | { 17 | return new CacheableResponse(response, expiration); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Nancy.LightningCache/LightningCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Threading; 5 | using Nancy.Bootstrapper; 6 | using Nancy.LightningCache.CacheKey; 7 | using Nancy.LightningCache.CacheStore; 8 | using Nancy.LightningCache.Projection; 9 | using Nancy.Routing; 10 | 11 | namespace Nancy.LightningCache 12 | { 13 | /// 14 | /// Asynchronous cache for Nancy 15 | /// 16 | public class LightningCache 17 | { 18 | private static readonly string NO_REQUEST_CACHE_KEY = "_lightningCacheDisabled"; 19 | 20 | private static ICacheStore _cacheStore; 21 | private static ICacheKeyGenerator _cacheKeyGenerator; 22 | 23 | private static bool _enabled; 24 | 25 | private static INancyEngine _nancyEngine; 26 | private static INancyEngine NancyEngine 27 | { 28 | get 29 | { 30 | _nancyEngine = _nancyEngine ?? _nancyBootstrapper.GetEngine(); 31 | return _nancyEngine; 32 | } 33 | } 34 | private static IRouteResolver _routeResolver; 35 | 36 | private static INancyBootstrapper _nancyBootstrapper; 37 | 38 | 39 | /// 40 | /// 41 | /// 42 | /// 43 | /// 44 | /// 45 | /// 46 | public static void Enable(INancyBootstrapper nancyBootstrapper, IRouteResolver routeResolver, IPipelines pipelines, string[] varyParams) 47 | { 48 | Enable(nancyBootstrapper, routeResolver, pipelines, new DefaultCacheKeyGenerator(varyParams), new WebCacheStore()); 49 | } 50 | 51 | /// 52 | /// 53 | /// 54 | /// 55 | /// 56 | /// 57 | /// 58 | public static void Enable(INancyBootstrapper nancyBootstrapper, IRouteResolver routeResolver, IPipelines pipelines, ICacheKeyGenerator cacheKeyGenerator) 59 | { 60 | Enable(nancyBootstrapper, routeResolver, pipelines, cacheKeyGenerator, new WebCacheStore()); 61 | } 62 | 63 | 64 | 65 | /// 66 | /// 67 | /// 68 | /// 69 | /// 70 | /// 71 | /// 72 | /// 73 | public static void Enable(INancyBootstrapper nancyBootstrapper, IRouteResolver routeResolver, IPipelines pipeline, ICacheKeyGenerator cacheKeyGenerator, ICacheStore cacheStore) 74 | { 75 | if (_enabled) 76 | return; 77 | _enabled = true; 78 | _cacheKeyGenerator = cacheKeyGenerator; 79 | _cacheStore = cacheStore; 80 | _nancyBootstrapper = nancyBootstrapper; 81 | _routeResolver = routeResolver; 82 | pipeline.BeforeRequest.AddItemToStartOfPipeline(CheckCache); 83 | pipeline.AfterRequest.AddItemToEndOfPipeline(SetCache); 84 | } 85 | 86 | /// 87 | /// Invokes pre-requirements such as authentication and stuff for the supplied context 88 | /// reference: https://github.com/NancyFx/Nancy/blob/master/src/Nancy/Routing/DefaultRequestDispatcher.cs 89 | /// 90 | /// 91 | /// 92 | private static Response InvokePreRequirements(NancyContext context) 93 | { 94 | var resolution = _routeResolver.Resolve(context); 95 | var preRequirements = resolution.Before; 96 | var task = preRequirements.Invoke(context, new CancellationToken(false)); 97 | task.Wait(); 98 | return context.Response; 99 | } 100 | 101 | /// 102 | /// checks current cachestore for a cached response and returns it 103 | /// 104 | /// 105 | /// cached response or null 106 | private static Response CheckCache(NancyContext context) 107 | { 108 | if (context.Request.Query is DynamicDictionary) 109 | if ((context.Request.Query as DynamicDictionary).ContainsKey(NO_REQUEST_CACHE_KEY)) 110 | return null; 111 | 112 | var key = _cacheKeyGenerator.Get(context.Request); 113 | 114 | if (string.IsNullOrEmpty(key)) 115 | return null; 116 | 117 | var response = _cacheStore.Get(key); 118 | 119 | if (response == null) 120 | return null; 121 | 122 | if (response.Expiration < DateTime.Now) 123 | { 124 | var t = new Thread(HandleRequestAsync); 125 | t.Start(context.Request); 126 | } 127 | 128 | //make damn sure the pre-requirements are met before returning a cached response 129 | var preResponse = InvokePreRequirements(context); 130 | if (preResponse != null) 131 | return preResponse; 132 | 133 | return response; 134 | } 135 | 136 | /// 137 | /// caches response before it is sent to client if it is a CacheableResponse or if the NegotationContext has the nancy-lightningcache header set. 138 | /// 139 | /// 140 | private static void SetCache(NancyContext context) 141 | { 142 | if (context.Response is CachedResponse) 143 | return; 144 | 145 | var key = _cacheKeyGenerator.Get(context.Request); 146 | 147 | if (string.IsNullOrEmpty(key)) 148 | return; 149 | 150 | if (context.Response is CacheableResponse) 151 | { 152 | if (context.Response.StatusCode != HttpStatusCode.OK) 153 | { 154 | _cacheStore.Remove(key); 155 | return; 156 | } 157 | _cacheStore.Set(key, context, (context.Response as CacheableResponse).Expiration); 158 | } 159 | else if (context.NegotiationContext != null && context.NegotiationContext.Headers != null && context.NegotiationContext.Headers.ContainsKey("nancy-lightningcache")) 160 | { 161 | if (context.Response.StatusCode != HttpStatusCode.OK) 162 | { 163 | _cacheStore.Remove(key); 164 | return; 165 | } 166 | var expiration = DateTime.Parse(context.NegotiationContext.Headers["nancy-lightningcache"], CultureInfo.InvariantCulture); 167 | context.NegotiationContext.Headers.Remove("nancy-lightningcache"); 168 | _cacheStore.Set(key, context, expiration); 169 | } 170 | } 171 | 172 | private static readonly List RequestSyncKeys = new List(); 173 | private static readonly object Lock = new object(); 174 | /// 175 | /// used to asynchronously cache Nancy Requests 176 | /// 177 | /// 178 | private static void HandleRequestAsync(object context) 179 | { 180 | lock (Lock) 181 | { 182 | var request = context as Request; 183 | 184 | if (request == null) 185 | return; 186 | 187 | var key = _cacheKeyGenerator.Get(request); 188 | 189 | if (string.IsNullOrEmpty(key)) 190 | return; 191 | 192 | try 193 | { 194 | if (RequestSyncKeys.Contains(key)) 195 | return; 196 | 197 | RequestSyncKeys.Add(key); 198 | 199 | request.Query[NO_REQUEST_CACHE_KEY] = NO_REQUEST_CACHE_KEY; 200 | 201 | var context2 = NancyEngine.HandleRequest(request); 202 | 203 | if (context2.Response.StatusCode != HttpStatusCode.OK) 204 | _cacheStore.Remove(key); 205 | } 206 | catch (Exception) 207 | { 208 | _cacheStore.Remove(key); 209 | } 210 | finally 211 | { 212 | RequestSyncKeys.Remove(key); 213 | } 214 | } 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /Nancy.LightningCache/Nancy.LightningCache.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {FDE0905B-F713-478C-83BC-9872631758FE} 8 | Library 9 | Properties 10 | Nancy.LightningCache 11 | Nancy.LightningCache 12 | v4.0 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | False 35 | ..\packages\Nancy.0.23.2\lib\net40\Nancy.dll 36 | 37 | 38 | False 39 | ..\packages\Nancy.Authentication.Forms.0.23.2\lib\net40\Nancy.Authentication.Forms.dll 40 | 41 | 42 | False 43 | ..\packages\Nancy.Hosting.Aspnet.0.23.2\lib\net40\Nancy.Hosting.Aspnet.dll 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 80 | -------------------------------------------------------------------------------- /Nancy.LightningCache/Nancy.LightningCache.csproj.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Nancy.LightningCache 5 | $version$ 6 | Christian Westman 7 | Christian Westman 8 | https://github.com/creamdog/Nancy.LightningCache 9 | false 10 | delivers dynamic content with the speed of static content using asyncronous caching 11 | updated to target Nancy 0.20.0. culture invariant datetime parsing. 12 | Copyright 2013 13 | nancy cache 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Nancy.LightningCache/Projection/CacheableResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Nancy.LightningCache.Projection 4 | { 5 | /// 6 | /// Cacheable Nancy Response 7 | /// 8 | public class CacheableResponse : Response 9 | { 10 | private readonly Response _response; 11 | 12 | public readonly DateTime Expiration; 13 | 14 | public CacheableResponse(Response response, DateTime expiration) 15 | { 16 | _response = response; 17 | Expiration = expiration; 18 | this.ContentType = response.ContentType; 19 | this.Headers = response.Headers; 20 | this.StatusCode = response.StatusCode; 21 | this.Contents = _response.Contents; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Nancy.LightningCache/Projection/CachedResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.IO; 4 | 5 | namespace Nancy.LightningCache.Projection 6 | { 7 | /// 8 | /// Cached Nancy Response 9 | /// 10 | public class CachedResponse : Response 11 | { 12 | public readonly string OldResponseOutput; 13 | 14 | public readonly DateTime Expiration; 15 | 16 | public CachedResponse(SerializableResponse response) 17 | { 18 | ContentType = response.ContentType; 19 | Headers = response.Headers; 20 | StatusCode = response.StatusCode; 21 | OldResponseOutput = response.Contents; 22 | Contents = GetContents(this.OldResponseOutput); 23 | Expiration = response.Expiration; 24 | 25 | Headers["X-Nancy-LightningCache-Expiration"] = response.Expiration.ToString(CultureInfo.InvariantCulture); 26 | } 27 | 28 | protected static Action GetContents(string contents) 29 | { 30 | return stream => 31 | { 32 | var writer = new StreamWriter(stream) { AutoFlush = true }; 33 | writer.Write(contents); 34 | }; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Nancy.LightningCache/Projection/SerializableResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Nancy.LightningCache.Projection 8 | { 9 | /// 10 | /// Persistable Nancy Response 11 | /// 12 | public class SerializableResponse 13 | { 14 | public SerializableResponse() 15 | { 16 | } 17 | 18 | public SerializableResponse(Response response, DateTime expiration) 19 | { 20 | this.Expiration = expiration; 21 | this.ContentType = response.ContentType; 22 | this.Headers = response.Headers; 23 | this.StatusCode = response.StatusCode; 24 | 25 | using (var memoryStream = new MemoryStream()) 26 | { 27 | response.Contents(memoryStream); 28 | this.Contents = Encoding.UTF8.GetString(memoryStream.GetBuffer().Where(a => a != 0).ToArray()); 29 | } 30 | } 31 | public string ContentType { get; set; } 32 | public IDictionary Headers { get; set; } 33 | public HttpStatusCode StatusCode { get; set; } 34 | public string Contents { get; set; } 35 | public DateTime Expiration { get; set; } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Nancy.LightningCache/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/Nancy.LightningCache/Properties/AssemblyInfo.cs -------------------------------------------------------------------------------- /Nancy.LightningCache/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Nancy.LightningCache 2 | ==================== 3 | 4 | Delivers dynamic content with the speed of static content using asyncronous caching. Nancy.LightningCache will allways deliver cached responses if they exist and update asynchronously if needed. 5 | 6 | ##Installation 7 | 8 | Install via nuget https://nuget.org/packages/Nancy.LightningCache 9 | 10 | ``` 11 | PM> Install-Package Nancy.LightningCache 12 | ``` 13 | 14 | Or build from source and drop Nancy.LightningCache.dll into your solution 15 | 16 | ##Example usage 17 | the following example is using the default "System.Web.Cache" CacheStore 18 | ###1. Add to your bootstrapper 19 | 20 | ```c# 21 | using Nancy.LightningCache.Extensions; 22 | using Nancy.Routing; 23 | 24 | namespace Asp.Net.Example 25 | { 26 | public class ApplicationBootrapper : Nancy.DefaultNancyBootstrapper 27 | { 28 | protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines) 29 | { 30 | base.ApplicationStartup(container, pipelines); 31 | /*enable lightningcache, vary by url params id,query,take and skip*/ 32 | this.EnableLightningCache(container.Resolve(), ApplicationPipelines, new[] { "id", "query", "take", "skip" }); 33 | } 34 | } 35 | } 36 | ``` 37 | 38 | ###2. Enable caching by adding "AsCacheable" to any of your routes 39 | ```c# 40 | using System; 41 | using Nancy; 42 | using Nancy.LightningCache.Extensions; 43 | 44 | namespace Asp.Net.Example 45 | { 46 | public class ExampleModule : NancyModule 47 | { 48 | public ExampleModule() 49 | { 50 | Get["/"] = _ => 51 | { 52 | /*cache view*/ 53 | return View["hello.html"].AsCacheable(DateTime.Now.AddSeconds(30)); 54 | }; 55 | 56 | Get["/CachedResponse"] = _ => 57 | { 58 | /*cache response*/ 59 | return Response.AsText("hello").AsCacheable(DateTime.Now.AddSeconds(30)); 60 | }; 61 | } 62 | } 63 | } 64 | ``` 65 | 66 | ##Example usage of the DiskCacheStore 67 | If your application does not have access to "System.Web.Cache" as in running in self hosting mode you can use the DiskCacheStore to enable caching thought LightningCache. 68 | ```c# 69 | using Nancy.LightningCache.CacheStore; 70 | using Nancy.LightningCache.Extensions; 71 | using Nancy.Routing; 72 | 73 | namespace Asp.Net.Example 74 | { 75 | public class ApplicationBootrapper : Nancy.DefaultNancyBootstrapper 76 | { 77 | protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines) 78 | { 79 | base.ApplicationStartup(container, pipelines); 80 | /*enable lightningcache using the DiskCacheStore, vary by url params id,query,take and skip*/ 81 | this.EnableLightningCache(container.Resolve(), ApplicationPipelines, new[] { "id", "query", "take", "skip" }, new DiskCacheStore("c:/tmp/cache")); 82 | } 83 | } 84 | } 85 | ``` 86 | 87 | ##Example definining your own cache key generation using ICacheKeyGenerator 88 | 89 | ```c# 90 | using System; 91 | using System.Text; 92 | using Nancy; 93 | using Nancy.LightningCache.Extensions; 94 | using Nancy.Routing; 95 | 96 | namespace WebApplication 97 | { 98 | public class Bootstrapper : Nancy.DefaultNancyBootstrapper 99 | { 100 | protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines) 101 | { 102 | base.ApplicationStartup(container, pipelines); 103 | this.EnableLightningCache(container.Resolve(), ApplicationPipelines, new UrlHashKeyGenerator()); 104 | } 105 | 106 | public class UrlHashKeyGenerator : Nancy.LightningCache.CacheKey.ICacheKeyGenerator 107 | { 108 | public string Get(Request request) 109 | { 110 | using(var md5 = new System.Security.Cryptography.MD5CryptoServiceProvider()) 111 | { 112 | var hash = md5.ComputeHash(Encoding.UTF8.GetBytes(request.Url.ToString())); 113 | return Convert.ToBase64String(hash); 114 | } 115 | } 116 | } 117 | } 118 | } 119 | ``` 120 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | .\tools\Phantom\phantom.exe -------------------------------------------------------------------------------- /build.boo: -------------------------------------------------------------------------------- 1 | solution_file = "Nancy.LightningCache.sln" 2 | configuration = "release" 3 | nextVersion = "0.1.2" 4 | 5 | target default, (updateVersion, compile, nuget): 6 | pass 7 | 8 | target updateVersion: 9 | exec("tools\\UpdateVersion.exe", "-p ${nextVersion} -i .\\Nancy.LightningCache\\Properties\\AssemblyInfo.cs -o .\\Nancy.LightningCache\\Properties\\AssemblyInfo.cs") 10 | 11 | target compile: 12 | msbuild(file: solution_file, configuration: configuration) 13 | 14 | target nuget: 15 | exec("Tools\\NuGet.exe", "pack .\\Nancy.LightningCache\\Nancy.LightningCache.csproj.nuspec -Version ${nextVersion} "); -------------------------------------------------------------------------------- /packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tools/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/NuGet.exe -------------------------------------------------------------------------------- /tools/Phantom/Boo.Lang.Compiler.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Boo.Lang.Compiler.dll -------------------------------------------------------------------------------- /tools/Phantom/Boo.Lang.Parser.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Boo.Lang.Parser.dll -------------------------------------------------------------------------------- /tools/Phantom/Boo.Lang.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Boo.Lang.dll -------------------------------------------------------------------------------- /tools/Phantom/EasyHttp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/EasyHttp.dll -------------------------------------------------------------------------------- /tools/Phantom/EasyHttp.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/EasyHttp.pdb -------------------------------------------------------------------------------- /tools/Phantom/Ionic.Zip.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Ionic.Zip.dll -------------------------------------------------------------------------------- /tools/Phantom/Microsoft.Web.Administration.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Microsoft.Web.Administration.dll -------------------------------------------------------------------------------- /tools/Phantom/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /tools/Phantom/Phantom.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Phantom.Core.dll -------------------------------------------------------------------------------- /tools/Phantom/Phantom.Core.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Phantom.Core.pdb -------------------------------------------------------------------------------- /tools/Phantom/Phantom.DSL.Boo.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Phantom.DSL.Boo.dll -------------------------------------------------------------------------------- /tools/Phantom/Phantom.DSL.Boo.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Phantom.DSL.Boo.pdb -------------------------------------------------------------------------------- /tools/Phantom/Phantom.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Phantom.exe -------------------------------------------------------------------------------- /tools/Phantom/Phantom.exe.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tools/Phantom/Phantom.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Phantom.pdb -------------------------------------------------------------------------------- /tools/Phantom/Phantom.vshost.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Phantom.vshost.exe -------------------------------------------------------------------------------- /tools/Phantom/Phantom.vshost.exe.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tools/Phantom/Phantom.vshost.exe.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tools/Phantom/PhantomContrib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/PhantomContrib.dll -------------------------------------------------------------------------------- /tools/Phantom/PhantomContrib.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/PhantomContrib.pdb -------------------------------------------------------------------------------- /tools/Phantom/Rhino.DSL.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Rhino.DSL.dll -------------------------------------------------------------------------------- /tools/Phantom/Tipser.Executionr.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Tipser.Executionr.dll -------------------------------------------------------------------------------- /tools/Phantom/Tipser.Executionr.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Tipser.Executionr.pdb -------------------------------------------------------------------------------- /tools/Phantom/Tipser.Versionator.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Tipser.Versionator.dll -------------------------------------------------------------------------------- /tools/Phantom/Tipser.Versionator.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/Phantom/Tipser.Versionator.pdb -------------------------------------------------------------------------------- /tools/UpdateVersion.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creamdog/Nancy.LightningCache/3d668ebf30aaee299fa6ee510c314f527828e24e/tools/UpdateVersion.exe --------------------------------------------------------------------------------