/// <summary> /// Called before an action method executes. /// </summary> /// <param name="filterContext">The filter context.</param> public override void OnActionExecuting(ActionExecutingContext filterContext) { CacheSettings = BuildCacheSettings(); var cacheKey = KeyGenerator.GenerateKey(filterContext, CacheSettings); // If we are unable to generate a cache key it means we can't do anything if (string.IsNullOrEmpty(cacheKey)) { return; } // Are we actually storing data on the server side ? if (CacheSettings.IsServerCachingEnabled) { CacheItem cachedItem = null; // If the request is a POST, we lookup for NoCacheLookupForPosts option // We are fetching the stored value only if the option has not been set and the request is not a POST if ( (CacheSettings.Options & OutputCacheOptions.NoCacheLookupForPosts) != OutputCacheOptions.NoCacheLookupForPosts || filterContext.HttpContext.Request.HttpMethod != "POST" ) { cachedItem = OutputCacheManager.GetItem(cacheKey); } // We have a cached version on the server side if (cachedItem != null) { // We inject the previous result into the MVC pipeline // The MVC action won't execute as we injected the previous cached result. filterContext.Result = new ContentResult { Content = DonutHoleFiller.ReplaceDonutHoleContent(cachedItem.Content, filterContext, CacheSettings.Options), ContentType = cachedItem.ContentType }; } } // Did we already injected something ? if (filterContext.Result != null) { return; // No need to continue } // We are hooking into the pipeline to replace the response Output writer // by something we own and later eventually gonna cache var cachingWriter = new StringWriter(CultureInfo.InvariantCulture); var originalWriter = filterContext.HttpContext.Response.Output; filterContext.HttpContext.Response.Output = cachingWriter; // Will be called back by OnResultExecuted -> ExecuteCallback filterContext.HttpContext.Items[cacheKey] = new Action<bool>(hasErrors => { // Removing this executing action from the context filterContext.HttpContext.Items.Remove(cacheKey); // We restore the original writer for response filterContext.HttpContext.Response.Output = originalWriter; if (hasErrors) { return; // Something went wrong, we are not going to cache something bad } // Now we use owned caching writer to actually store data var cacheItem = new CacheItem { Content = cachingWriter.ToString(), ContentType = filterContext.HttpContext.Response.ContentType }; filterContext.HttpContext.Response.Write( DonutHoleFiller.RemoveDonutHoleWrappers(cacheItem.Content, filterContext, CacheSettings.Options) ); if (CacheSettings.IsServerCachingEnabled && filterContext.HttpContext.Response.StatusCode == 200) { OutputCacheManager.AddItem(cacheKey, cacheItem, DateTime.UtcNow.AddSeconds(CacheSettings.Duration)); } }); }
public void AddItem(string key, CacheItem cacheItem, DateTime utcExpiry) { _outputCacheProvider.Add(key, cacheItem, utcExpiry); }
/// <summary> /// Called before an action method executes. /// </summary> /// <param name="filterContext">The filter context.</param> public override void OnActionExecuting(ActionExecutingContext filterContext) { CacheSettings = BuildCacheSettings(); var cacheKey = KeyGenerator.GenerateKey(filterContext, CacheSettings); // If we are unable to generate a cache key it means we can't do anything if (string.IsNullOrEmpty(cacheKey)) { return; } // Are we actually storing data on the server side ? if (CacheSettings.IsServerCachingEnabled) { CacheItem cachedItem = null; // If the request is a POST, we lookup for NoCacheLookupForPosts option // We are fetching the stored value only if the option has not been set and the request is not a POST if ( (CacheSettings.Options & OutputCacheOptions.NoCacheLookupForPosts) != OutputCacheOptions.NoCacheLookupForPosts || filterContext.HttpContext.Request.HttpMethod != "POST" ) { cachedItem = OutputCacheManager.GetItem(cacheKey); } // We have a cached version on the server side if (cachedItem != null) { // We inject the previous result into the MVC pipeline // The MVC action won't execute as we injected the previous cached result. filterContext.Result = new DonutContentResult { Content = DonutHoleFiller.ReplaceDonutHoleContent(cachedItem.Content, cachedItem.ContentType, filterContext, CacheSettings.Options), ContentType = cachedItem.ContentType }; } } // Did we already injected something ? if (filterContext.Result != null) { return; // No need to continue } // We are hooking into the pipeline to replace the response Output writer // by something we own and later eventually gonna cache var cachingWriter = new StringWriter(CultureInfo.InvariantCulture); var originalWriter = filterContext.HttpContext.Response.Output; filterContext.HttpContext.Response.Output = cachingWriter; // Will be called back by OnResultExecuted -> ExecuteCallback filterContext.HttpContext.Items[cacheKey] = new Action <bool>(hasErrors => { // Removing this executing action from the context filterContext.HttpContext.Items.Remove(cacheKey); // We restore the original writer for response filterContext.HttpContext.Response.Output = originalWriter; if (hasErrors) { return; // Something went wrong, we are not going to cache something bad } // Now we use owned caching writer to actually store data var cacheItem = new CacheItem { Content = cachingWriter.ToString(), ContentType = filterContext.HttpContext.Response.ContentType }; filterContext.HttpContext.Response.Write( DonutHoleFiller.RemoveDonutHoleWrappers(cacheItem.Content, filterContext, CacheSettings.Options) ); // Skip saving the cache if ignored for current execution if (OutputCacheManager.GetIgnoreCurrentExecution(filterContext)) { OutputCacheManager.RemoveIgnoreCurrentExecution(filterContext); return; // Skip current execution from cache } if (CacheSettings.IsServerCachingEnabled && filterContext.HttpContext.Response.StatusCode == 200) { OutputCacheManager.AddItem(cacheKey, cacheItem, DateTime.UtcNow.AddSeconds(CacheSettings.Duration)); } }); }
public override void OnActionExecuting(ActionExecutingContext filterContext) { _cacheSettings = BuildCacheSettings(); var cacheKey = _keyGenerator.GenerateKey(filterContext, _cacheSettings); if (_cacheSettings.IsServerCachingEnabled) { var cachedItem = _outputCacheManager.GetItem(cacheKey); if (cachedItem != null) { filterContext.Result = new ContentResult { Content = _donutHoleFiller.ReplaceDonutHoleContent(cachedItem.Content, filterContext), ContentType = cachedItem.ContentType }; } } if (filterContext.Result == null) { var cachingWriter = new StringWriter(CultureInfo.InvariantCulture); var originalWriter = filterContext.HttpContext.Response.Output; filterContext.HttpContext.Response.Output = cachingWriter; filterContext.HttpContext.Items[cacheKey] = new Action<bool>(hasErrors => { filterContext.HttpContext.Items.Remove(cacheKey); filterContext.HttpContext.Response.Output = originalWriter; if (!hasErrors) { var cacheItem = new CacheItem { Content = cachingWriter.ToString(), ContentType = filterContext.HttpContext.Response.ContentType }; filterContext.HttpContext.Response.Write(_donutHoleFiller.RemoveDonutHoleWrappers(cacheItem.Content, filterContext)); if (_cacheSettings.IsServerCachingEnabled && filterContext.HttpContext.Response.StatusCode == 200) { _outputCacheManager.AddItem(cacheKey, cacheItem, DateTime.UtcNow.AddSeconds(_cacheSettings.Duration)); } } }); } }