using System; using System.Web; using System.Web.Configuration; using System.Web.Mvc; namespace Website.Filters { [Flags] public enum CacheType { ClientSide, ServerSide } public class CacheableAttribute : ActionFilterAttribute { private static bool? cachingEnabled; /// /// Is Caching Enabled in the application configuration? /// public static bool OutputCachingEnabled { get { if (!cachingEnabled.HasValue) { var outputSettings = (OutputCacheSection)WebConfigurationManager .GetWebApplicationSection("system.web/caching/outputCache"); cachingEnabled = (outputSettings == null || outputSettings.EnableOutputCache); } return cachingEnabled.Value; } } /// /// Is caching enabled?
/// Use this to override the default and always explicitly /// enabled or disable caching on this particular Action.
/// (Default = value of system.web/caching/outputCache/EnableOutputCache configuration setting) ///
public bool Enabled { get; set; } #region Supported Types (SupportedTypes, ClientCachingEnabled, and ServerCachingEnabled properties) /// /// The types of caching supported on this Action. /// Defaults to both server- and client-side caching. /// public CacheType SupportedTypes { get; set; } protected bool ClientCachingEnabled { get { return Enabled && IsCacheTypeEnabled(CacheType.ClientSide); } } protected bool ServerCachingEnabled { get { return Enabled && IsCacheTypeEnabled(CacheType.ServerSide); } } private bool IsCacheTypeEnabled(CacheType type) { // Perform a bitwise operation to see whether or not this type is enabled. return (SupportedTypes & type) == type; } #endregion /// /// Maximum time (in minutes) for this content /// to remain cached on the client. /// public double ClientMaxAge { get; set; } public CacheableAttribute() { // Set the Enabled default to that of the Output Caching Enabled = OutputCachingEnabled; // Default to both client- & server-side caching. SupportedTypes = CacheType.ServerSide & CacheType.ClientSide; // Default to 3 days (60 mins * 24 hrs * 3 days) ClientMaxAge = 60 * 24 * 3; } public override void OnResultExecuted(ResultExecutedContext filterContext) { // If client-side caching isn't enabled, just return now. if (!ClientCachingEnabled) return; // Otherwise, configure the caching headers. var cache = filterContext.HttpContext.Response.Cache; var duration = TimeSpan.FromMinutes(ClientMaxAge); cache.SetCacheability(HttpCacheability.Public); cache.SetExpires(DateTime.Now.Add(duration)); cache.SetMaxAge(duration); cache.AppendCacheExtension("must-revalidate"); } } }