Skip to content

Commit

Permalink
Implement abstract cache buster: ICacheBuster #51
Browse files Browse the repository at this point in the history
  • Loading branch information
Shazwazza committed Nov 18, 2016
1 parent 2c38fa5 commit c60034c
Show file tree
Hide file tree
Showing 19 changed files with 256 additions and 44 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -189,3 +189,4 @@ src/Smidge.Web/App_Data/Smidge/*
/src/Smidge.Web/project.lock.json
/tests/Smidge.Tests/project.lock.json
test/Smidge.Tests/project.lock.json
test/Smidge.Benchmarks/BenchmarkDotNet.Artifacts/*
2 changes: 0 additions & 2 deletions .vs/restore.dg

This file was deleted.

38 changes: 34 additions & 4 deletions src/Smidge.Web/Startup.cs
@@ -1,13 +1,18 @@
using System.IO;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.PlatformAbstractions;
using Smidge.Cache;
using Smidge.Options;
using Smidge.Models;
using Smidge.FileProcessors;
using Smidge.JavaScriptServices;
using Smidge.Nuglify;

namespace Smidge.Web
{
Expand Down Expand Up @@ -47,15 +52,39 @@ public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ApplicationEnvironment>();

services.AddMvc();
services.AddMvc();

// Or use services.AddSmidge() to test from smidge.json config.
services.AddSmidge(_config)
//Set the global Smidge options
.Configure<SmidgeOptions>(options =>
{
//options.FileWatchOptions.Enabled = true;
options.PipelineFactory.OnGetDefault = GetDefaultPipelineFactory;
options.DefaultBundleOptions.DebugOptions.SetCacheBusterType<AppDomainLifetimeCacheBuster>();
});

services.AddSmidgeJavaScriptServices();
services.AddSmidgeNuglifyServices();
}

/// <summary>
/// A callback used to modify the default pipeline to use Nuglify for JS processing
/// </summary>
/// <param name="fileType"></param>
/// <param name="processors"></param>
/// <returns></returns>
private static PreProcessPipeline GetDefaultPipelineFactory(WebFileType fileType, IReadOnlyCollection<IPreProcessor> processors)
{
switch (fileType)
{
case WebFileType.Js:
return new PreProcessPipeline(new IPreProcessor[]
{
processors.OfType<NuglifyJs>().Single()
});
}
//returning null will fallback to the logic defined in the registered PreProcessPipelineFactory
return null;
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
Expand Down Expand Up @@ -95,12 +124,13 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
//return some custom ordering
return collection.OrderBy(x => x.FilePath);
});
bundles.Create("test-bundle-2", WebFileType.Js, "~/Js/Bundle2")
.WithEnvironmentOptions(BundleEnvironmentOptions.Create()
.ForDebug(builder => builder
.EnableCompositeProcessing()
.EnableFileWatcher()
.SetCacheBusterType<AppDomainLifetimeCacheBuster>()
.CacheControlOptions(enableEtag: false, cacheControlMaxAge: 0))
.Build()
);
Expand Down
26 changes: 26 additions & 0 deletions src/Smidge/Cache/AppDomainLifetimeCacheBuster.cs
@@ -0,0 +1,26 @@
using System;
using System.Globalization;

namespace Smidge.Cache
{
/// <summary>
/// Creates a cache bust value for the lifetime of the app domain
/// </summary>
/// <remarks>
/// Essentially means that all caches will be busted when the app restarts
/// </remarks>
public class AppDomainLifetimeCacheBuster : ICacheBuster
{
public AppDomainLifetimeCacheBuster()
{
_value = new Lazy<string>(() => DateTime.UtcNow.Ticks.ToString(NumberFormatInfo.InvariantInfo));
}

private static Lazy<string> _value;

public string GetValue()
{
return _value.Value;
}
}
}
29 changes: 29 additions & 0 deletions src/Smidge/Cache/CacheBusterResolver.cs
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Smidge.Cache
{
/// <summary>
/// Used to resolve an instance of ICacheBuster from the registered ones in the container
/// </summary>
public sealed class CacheBusterResolver
{
private readonly IEnumerable<ICacheBuster> _cacheBusters;

public CacheBusterResolver(IEnumerable<ICacheBuster> cacheBusters)
{
_cacheBusters = cacheBusters;
}

/// <summary>
/// Get the cache buster for the given type
/// </summary>
/// <param name="busterType"></param>
/// <returns></returns>
public ICacheBuster GetCacheBuster(Type busterType)
{
return _cacheBusters.FirstOrDefault(x => x.GetType() == busterType);
}
}
}
23 changes: 23 additions & 0 deletions src/Smidge/Cache/ConfigCacheBuster.cs
@@ -0,0 +1,23 @@
using System;
using System.Collections;

namespace Smidge.Cache
{
/// <summary>
/// Based on a static string specified in config
/// </summary>
public class ConfigCacheBuster : ICacheBuster
{
private readonly ISmidgeConfig _config;

public ConfigCacheBuster(ISmidgeConfig config)
{
if (config == null) throw new ArgumentNullException(nameof(config));
_config = config;
}
public string GetValue()
{
return _config.Version;
}
}
}
14 changes: 14 additions & 0 deletions src/Smidge/Cache/ICacheBuster.cs
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Smidge.Cache
{
/// <summary>
/// Returns the value to cache bust the request
/// </summary>
public interface ICacheBuster
{
string GetValue();
}
}
25 changes: 14 additions & 11 deletions src/Smidge/CompositeFiles/DefaultUrlManager.cs
Expand Up @@ -4,28 +4,29 @@
using System.Text;
using System.Linq;
using Microsoft.Extensions.Options;
using Smidge.Cache;
using Smidge.Options;
using Smidge.Hashing;

namespace Smidge.CompositeFiles
{
public class DefaultUrlManager : IUrlManager
{
private readonly ISmidgeConfig _config;
private readonly IHasher _hasher;
private readonly IRequestHelper _requestHelper;
private readonly UrlManagerOptions _options;

public DefaultUrlManager(IOptions<SmidgeOptions> options, ISmidgeConfig config, IHasher hasher, IRequestHelper requestHelper)
public DefaultUrlManager(IOptions<SmidgeOptions> options, IHasher hasher, IRequestHelper requestHelper)
{
_hasher = hasher;
_requestHelper = requestHelper;
_options = options.Value.UrlOptions;
_config = config;
}

public string GetUrl(string bundleName, string fileExtension, bool debug)
public string GetUrl(string bundleName, string fileExtension, bool debug, ICacheBuster cacheBuster)
{
if (cacheBuster == null) throw new ArgumentNullException(nameof(cacheBuster));

const string handler = "~/{0}/{1}{2}.{3}{4}";
return _requestHelper.Content(
string.Format(
Expand All @@ -34,12 +35,14 @@ public string GetUrl(string bundleName, string fileExtension, bool debug)
Uri.EscapeUriString(bundleName),
fileExtension,
debug ? 'd' : 'v',
_config.Version));
cacheBuster.GetValue()));

}

public IEnumerable<FileSetUrl> GetUrls(IEnumerable<IWebFile> dependencies, string fileExtension)
public IEnumerable<FileSetUrl> GetUrls(IEnumerable<IWebFile> dependencies, string fileExtension, ICacheBuster cacheBuster)
{
if (cacheBuster == null) throw new ArgumentNullException(nameof(cacheBuster));

var files = new List<FileSetUrl>();
var currBuilder = new StringBuilder();
var delimitedBuilder = new StringBuilder();
Expand All @@ -57,7 +60,7 @@ public IEnumerable<FileSetUrl> GetUrls(IEnumerable<IWebFile> dependencies, strin
if ((delimitedBuilder.Length
+ _options.CompositeFilePath.Length
+ fileExtension.Length
+ _config.Version.Length
+ cacheBuster.GetValue().Length
//this number deals with slashes, etc...
+ 10)
>= (_options.MaxUrlLength))
Expand All @@ -73,7 +76,7 @@ public IEnumerable<FileSetUrl> GetUrls(IEnumerable<IWebFile> dependencies, strin
files.Add(new FileSetUrl
{
Key = _hasher.Hash(output),
Url = GetCompositeUrl(output, fileExtension)
Url = GetCompositeUrl(output, fileExtension, cacheBuster)
});
//create some new output
currBuilder = new StringBuilder();
Expand All @@ -96,7 +99,7 @@ public IEnumerable<FileSetUrl> GetUrls(IEnumerable<IWebFile> dependencies, strin
files.Add(new FileSetUrl
{
Key = _hasher.Hash(output),
Url = GetCompositeUrl(output, fileExtension)
Url = GetCompositeUrl(output, fileExtension, cacheBuster)
});
}

Expand Down Expand Up @@ -139,7 +142,7 @@ public ParsedUrlPath ParsePath(string input)
return result;
}

private string GetCompositeUrl(string fileKey, string fileExtension)
private string GetCompositeUrl(string fileKey, string fileExtension, ICacheBuster cacheBuster)
{
//Create a delimited URL query string

Expand All @@ -150,7 +153,7 @@ private string GetCompositeUrl(string fileKey, string fileExtension)
_options.CompositeFilePath,
Uri.EscapeUriString(fileKey),
fileExtension,
_config.Version));
cacheBuster.GetValue()));
}
}
}
5 changes: 3 additions & 2 deletions src/Smidge/CompositeFiles/IUrlManager.cs
Expand Up @@ -2,14 +2,15 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Smidge.Cache;

namespace Smidge.CompositeFiles
{
public interface IUrlManager
{
string GetUrl(string bundleName, string fileExtension, bool debug);
string GetUrl(string bundleName, string fileExtension, bool debug, ICacheBuster cacheBuster);

IEnumerable<FileSetUrl> GetUrls(IEnumerable<IWebFile> dependencies, string fileExtension);
IEnumerable<FileSetUrl> GetUrls(IEnumerable<IWebFile> dependencies, string fileExtension, ICacheBuster cacheBuster);

ParsedUrlPath ParsePath(string input);
}
Expand Down
15 changes: 15 additions & 0 deletions src/Smidge/Models/BundleExtensions.cs
Expand Up @@ -19,5 +19,20 @@ public static BundleOptions GetBundleOptions(this Bundle bundle, IBundleManager

return bundleOptions;
}

/// <summary>
/// Gets the default bundle options based on whether we're in debug or not
/// </summary>
/// <param name="bundleMgr"></param>
/// <param name="debug"></param>
/// <returns></returns>
public static BundleOptions GetDefaultBundleOptions(this IBundleManager bundleMgr, bool debug)
{
var bundleOptions = debug
? bundleMgr.DefaultBundleOptions.DebugOptions
: bundleMgr.DefaultBundleOptions.ProductionOptions;

return bundleOptions;
}
}
}
7 changes: 5 additions & 2 deletions src/Smidge/Options/BundleEnvironmentOptions.cs
@@ -1,4 +1,7 @@
namespace Smidge.Options
using System;
using Smidge.Cache;

namespace Smidge.Options
{


Expand Down Expand Up @@ -35,7 +38,7 @@ public BundleEnvironmentOptions()
};
ProductionOptions = new BundleOptions();
}

/// <summary>
/// The options for debug mode
/// </summary>
Expand Down
40 changes: 39 additions & 1 deletion src/Smidge/Options/BundleOptions.cs
@@ -1,5 +1,10 @@
namespace Smidge.Options
using System;
using Smidge.Cache;

namespace Smidge.Options
{


/// <summary>
/// Defines options for a particular bundle
/// </summary>
Expand All @@ -14,8 +19,41 @@ public BundleOptions()
CacheControlOptions = new CacheControlOptions();
ProcessAsCompositeFile = true;
CompressResult = true;

}

private Type _defaultCacheBuster;

/// <summary>
/// Sets the default cache buster type
/// </summary>
/// <typeparam name="T"></typeparam>
/// <remarks>
/// This instance will be resolved from IoC at runtime
/// </remarks>
public void SetCacheBusterType<T>()
where T: ICacheBuster
{
_defaultCacheBuster = typeof(T);
}

/// <summary>
/// Returns the default cache buster type
/// </summary>
/// <returns></returns>
/// <remarks>
/// By default this is the ConfigCacheBuster
/// </remarks>
public Type GetCacheBusterType()
{
return _defaultCacheBuster ?? typeof(ConfigCacheBuster);
}

///// <summary>
///// Gets/sets the cache buster
///// </summary>
//public ICacheBuster CacheBuster { get; set; }

/// <summary>
/// If set to true, will process the bundle as composite files and combine them into a single file
/// </summary>
Expand Down

0 comments on commit c60034c

Please sign in to comment.