public void Set(string key, CacheItem cacheItem)
 {
     _workContext.HttpContext.Cache.Add(
         key,
         cacheItem,
         null,
         cacheItem.ValidUntilUtc,
         System.Web.Caching.Cache.NoSlidingExpiration,
         System.Web.Caching.CacheItemPriority.Normal,
         null);
 }
        public void Set(string key, CacheItem cacheItem) {
            var record = _repository.Table.FirstOrDefault(x => x.CacheKey == key);

            if (record == null) {
                record = new CacheItemRecord();
                Convert(cacheItem, record);
                _repository.Create(record);
                return;
            }

            Convert(cacheItem, record);
        }
 private void Convert(CacheItem cacheItem, CacheItemRecord record) {
     record.CacheKey = cacheItem.CacheKey;
     record.CachedOnUtc = cacheItem.CachedOnUtc;
     record.ContentType = cacheItem.ContentType;
     record.InvariantCacheKey = cacheItem.InvariantCacheKey;
     record.Output = cacheItem.Output;
     record.QueryString = cacheItem.QueryString;
     record.StatusCode = cacheItem.StatusCode;
     record.Tags = String.Join(";", cacheItem.Tags);
     record.Tenant = cacheItem.Tenant;
     record.Url = cacheItem.Url;
     record.ValidUntilUtc = cacheItem.ValidUntilUtc;
 }
        private CacheItem Convert(CacheItemRecord record) {
            var cacheItem = new CacheItem();

            cacheItem.CacheKey = record.CacheKey;
            cacheItem.CachedOnUtc = record.CachedOnUtc;
            cacheItem.ContentType = record.ContentType;
            cacheItem.InvariantCacheKey = record.InvariantCacheKey;
            cacheItem.Output = record.Output;
            cacheItem.QueryString = record.QueryString;
            cacheItem.StatusCode = record.StatusCode;
            cacheItem.Tags = record.Tags.Split(';');
            cacheItem.Tenant = record.Tenant;
            cacheItem.Url = record.Url;
            cacheItem.ValidUntilUtc = record.ValidUntilUtc;

            return cacheItem;
        }
        /// <summary>
        /// Define valid cache control values
        /// </summary>
        private void ApplyCacheControl(CacheItem cacheItem, HttpResponseBase response, string content)
        {
            if (_maxAge > 0) {
                var maxAge = new TimeSpan(0, 0, 0, _maxAge); //cacheItem.ValidUntilUtc - _clock.UtcNow;
                if (maxAge.TotalMilliseconds < 0) {
                    maxAge = TimeSpan.FromSeconds(0);
                }

                response.Cache.SetCacheability(HttpCacheability.Public);
                response.Cache.SetMaxAge(maxAge);
            }

            response.Cache.SetETag(content.GetHashCode().ToString(CultureInfo.InvariantCulture));

            response.Cache.SetOmitVaryStar(true);

            // different tenants with the same urls have different entries
            response.Cache.VaryByHeaders["HOST"] = true;

            // Set the Vary: Accept-Encoding response header.
            // This instructs the proxies to cache two versions of the resource: one compressed, and one uncompressed.
            // The correct version of the resource is delivered based on the client request header.
            // This is a good choice for applications that are singly homed and depend on public proxies for user locality.
            response.Cache.VaryByHeaders["Accept-Encoding"] = true;

            // create a unique cache per browser, in case a Theme is rendered differently (e.g., mobile)
            // c.f. http://msdn.microsoft.com/en-us/library/aa478965.aspx
            // c.f. http://stackoverflow.com/questions/6007287/outputcache-varybyheader-user-agent-or-varybycustom-browser
            response.Cache.SetVaryByCustom("browser");

            // enabling this would create an entry for each different browser sub-version
            // response.Cache.VaryByHeaders.UserAgent = true;
        }
        public void OnResultExecuted(ResultExecutedContext filterContext)
        {
            var response = filterContext.HttpContext.Response;

            // save the result only if the content can be intercepted
            if (_filter == null) return;

            // only for ViewResult right now, as we don't want to handle redirects, HttpNotFound, ...
            if (filterContext.Result as ViewResultBase == null) {
                Logger.Debug("Ignoring none ViewResult response");
                return;
            }

            // check if there is a specific rule not to cache the whole route
            var configurations = _cacheService.GetRouteConfigurations();
            var route = filterContext.Controller.ControllerContext.RouteData.Route;
            var key = _cacheService.GetRouteDescriptorKey(filterContext.HttpContext, route);
            var configuration = configurations.FirstOrDefault(c => c.RouteKey == key);

            // do not cache ?
            if (configuration != null && configuration.Duration == 0)
            {
                return;
            }

            // ignored url ?
            if (IsIgnoredUrl(filterContext.RequestContext.HttpContext.Request.AppRelativeCurrentExecutionFilePath, _ignoredUrls))
            {
                return;
            }

            // get contents

            response.Flush();
            var output = _filter.GetContents(response.ContentEncoding);

            if (String.IsNullOrWhiteSpace(output))
            {
                return;
            }

            var tokenIndex = output.IndexOf(AntiforgeryTag, StringComparison.Ordinal);

            // substitute antiforgery token by a beacon
            if (tokenIndex != -1)
            {
                var tokenEnd = output.IndexOf(">", tokenIndex, StringComparison.Ordinal);
                var sb = new StringBuilder();
                sb.Append(output.Substring(0, tokenIndex));
                sb.Append(AntiforgeryBeacon);
                sb.Append(output.Substring(tokenEnd + 1));

                output = sb.ToString();
            }

            // default duration of specific one ?
            var cacheDuration = configuration != null && configuration.Duration.HasValue ? configuration.Duration.Value : _cacheDuration;

            // include each of the content item ids as tags for the cache entry
            var contentItemIds = _displayedContentItemHandler.GetDisplayed().Select(x => x.ToString(CultureInfo.InvariantCulture)).ToArray();

            var cacheItem = new CacheItem
            {
                ContentType = response.ContentType,
                StatusCode = response.StatusCode,
                CachedOnUtc = _now,
                ValidUntilUtc = _now.AddSeconds(cacheDuration),
                QueryString = filterContext.HttpContext.Request.Url.Query,
                Output = output,
                CacheKey = _cacheKey,
                InvariantCacheKey = _invariantCacheKey,
                Tenant = _shellSettings.Name,
                Url = filterContext.HttpContext.Request.Url.AbsolutePath,
                Tags = new[] { _invariantCacheKey }.Union(contentItemIds).ToArray()
            };

            ApplyCacheControl(cacheItem, response, output);

            Logger.Debug("Cache item added: " + cacheItem.CacheKey);

            // remove old cache data
            _cacheService.RemoveByTag(_invariantCacheKey);

            // add data to cache
            _cacheStorageProvider.Set(_cacheKey, cacheItem);

            // add to the tags index
            foreach (var tag in cacheItem.Tags) {
                _tagCache.Tag(tag, _cacheKey);
            }
        }
        public void OnResultExecuted(ResultExecutedContext filterContext)
        {
            var response = filterContext.HttpContext.Response;

            // save the result only if the content can be intercepted
            if (_filter == null) return;

            // only for ViewResult right now, as we don't want to handle redirects, HttpNotFound, ...
            if (filterContext.Result as ViewResultBase == null) {
                Logger.Debug("Ignoring none ViewResult response");
                return;
            }

            // check if there is a specific rule not to cache the whole route
            var configurations = _cacheService.GetRouteConfigurations();
            var route = filterContext.Controller.ControllerContext.RouteData.Route;
            var key = _cacheService.GetRouteDescriptorKey(filterContext.HttpContext, route);
            var configuration = configurations.FirstOrDefault(c => c.RouteKey == key);

            // do not cache ?
            if (configuration != null && configuration.Duration == 0)
            {
                return;
            }

            // ignored url ?
            if (IsIgnoredUrl(filterContext.RequestContext.HttpContext.Request.AppRelativeCurrentExecutionFilePath, _ignoredUrls))
            {
                return;
            }

            // get contents

            response.Flush();
            var output = _filter.GetContents(response.ContentEncoding);

            if (String.IsNullOrWhiteSpace(output))
            {
                return;
            }

            var tokenIndex = output.IndexOf(AntiforgeryTag, StringComparison.Ordinal);

            // substitute antiforgery token by a beacon
            if (tokenIndex != -1)
            {
                var tokenEnd = output.IndexOf(">", tokenIndex, StringComparison.Ordinal);
                var sb = new StringBuilder();
                sb.Append(output.Substring(0, tokenIndex));
                sb.Append(AntiforgeryBeacon);
                sb.Append(output.Substring(tokenEnd + 1));

                output = sb.ToString();
            }

            // default duration of specific one ?
            var cacheDuration = configuration != null && configuration.Duration.HasValue ? configuration.Duration.Value : _cacheDuration;

            var cacheItem = new CacheItem
            {
                ContentType = response.ContentType,
                StatusCode = response.StatusCode,
                CachedOnUtc = _now,
                ValidUntilUtc = _now.AddSeconds(cacheDuration),
                QueryString = filterContext.HttpContext.Request.Url.Query,
                Output = output,
                CacheKey = _cacheKey,
                InvariantCacheKey = _invariantCacheKey,
                Tenant = _shellSettings.Name,
                Url = filterContext.HttpContext.Request.Url.AbsolutePath
            };

            ApplyCacheControl(cacheItem, response, output);

            Logger.Debug("Cache item added: " + cacheItem.CacheKey);

            // remove old cache data
            RemoveFromCache(filterContext.HttpContext, item => item.InvariantCacheKey.Equals(_invariantCacheKey, StringComparison.OrdinalIgnoreCase));

            // add data to cache
            filterContext.HttpContext.Cache.Add(
                _cacheKey,
                cacheItem,
                null,
                cacheItem.ValidUntilUtc,
                System.Web.Caching.Cache.NoSlidingExpiration,
                System.Web.Caching.CacheItemPriority.Normal,
                null);
        }