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)); } } }); } }
/// <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); // 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)); } }); }