protected virtual bool ResponseIsCacheable(ResultExecutedContext filterContext, CacheRouteConfig configuration) { if (filterContext.HttpContext.Request.Url == null) { return false; } // Don't cache non-200 responses or results of a redirect. var response = filterContext.HttpContext.Response; if (response.StatusCode != (int)HttpStatusCode.OK || _transformRedirect) { return false; } // Don't cache in individual route configuration says no. if (configuration != null && configuration.Duration == 0) { Logger.Debug("Response for item '{0}' will not be cached because route is configured to not be cached.", _cacheKey); return false; } // Don't cache if request created notifications. var hasNotifications = !String.IsNullOrEmpty(Convert.ToString(filterContext.Controller.TempData["messages"])); if (hasNotifications) { Logger.Debug("Response for item '{0}' will not be cached because one or more notifications were created.", _cacheKey); return false; } return true; }
public void OnActionExecuting(ActionExecutingContext filterContext) { Logger.Debug("Incoming request for URL '{0}'.", filterContext.RequestContext.HttpContext.Request.RawUrl); // This filter is not reentrant (multiple executions within the same request are // not supported) so child actions are ignored completely. if (filterContext.IsChildAction) { Logger.Debug("Action '{0}' ignored because it's a child action.", filterContext.ActionDescriptor.ActionName); return; } _now = _clock.UtcNow; _workContext = _workContextAccessor.GetContext(); var configurations = _cacheService.GetRouteConfigs(); if (configurations.Any()) { var route = filterContext.Controller.ControllerContext.RouteData.Route; var key = _cacheService.GetRouteDescriptorKey(filterContext.HttpContext, route); _cacheRouteConfig = configurations.FirstOrDefault(c => c.RouteKey == key); } if (!RequestIsCacheable(filterContext)) return; // Computing the cache key after we know that the request is cacheable means that we are only performing this calculation on requests that require it _cacheKey = String.Intern(ComputeCacheKey(filterContext, GetCacheKeyParameters(filterContext))); _invariantCacheKey = ComputeCacheKey(filterContext, null); Logger.Debug("Cache key '{0}' was created.", _cacheKey); try { // Is there a cached item, and are we allowed to serve it? var allowServeFromCache = filterContext.RequestContext.HttpContext.Request.Headers["Cache-Control"] != "no-cache" || CacheSettings.IgnoreNoCache; var cacheItem = GetCacheItem(_cacheKey); if (allowServeFromCache && cacheItem != null) { Logger.Debug("Item '{0}' was found in cache.", _cacheKey); // Is the cached item in its grace period? if (cacheItem.IsInGracePeriod(_now)) { // Render the content unless another request is already doing so. if (Monitor.TryEnter(_cacheKey)) { Logger.Debug("Item '{0}' is in grace period and not currently being rendered; rendering item...", _cacheKey); BeginRenderItem(filterContext); return; } } // Cached item is not yet in its grace period, or is already being // rendered by another request; serve it from cache. Logger.Debug("Serving item '{0}' from cache.", _cacheKey); ServeCachedItem(filterContext, cacheItem); return; } // No cached item found, or client doesn't want it; acquire the cache key // lock to render the item. Logger.Debug("Item '{0}' was not found in cache or client refuses it. Acquiring cache key lock...", _cacheKey); if (Monitor.TryEnter(_cacheKey)) { Logger.Debug("Cache key lock for item '{0}' was acquired.", _cacheKey); // Item might now have been rendered and cached by another request; if so serve it from cache. if (allowServeFromCache) { cacheItem = GetCacheItem(_cacheKey); if (cacheItem != null) { Logger.Debug("Item '{0}' was now found; releasing cache key lock and serving from cache.", _cacheKey); Monitor.Exit(_cacheKey); ServeCachedItem(filterContext, cacheItem); return; } } } // Either we acquired the cache key lock and the item was still not in cache, or // the lock acquisition timed out. In either case render the item. Logger.Debug("Rendering item '{0}'...", _cacheKey); BeginRenderItem(filterContext); } catch { // Remember to release the cache key lock in the event of an exception! Logger.Debug("Exception occurred for item '{0}'; releasing any acquired lock.", _cacheKey); ReleaseCacheKeyLock(); throw; } }