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;
        }
예제 #2
0
        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;
            }
        }