public void SetCacheHeaders(HttpResponseBase response, CacheSettings settings)
        {
            var cacheability = HttpCacheability.NoCache;

            switch (settings.Location)
            {
                case OutputCacheLocation.Any:
                case OutputCacheLocation.Downstream:
                    cacheability = HttpCacheability.Public;
                    break;
                case OutputCacheLocation.Client:
                case OutputCacheLocation.ServerAndClient:
                    cacheability = HttpCacheability.Private;
                    break;
            }

            response.Cache.SetCacheability(cacheability);

            if (cacheability != HttpCacheability.NoCache)
            {
                response.Cache.SetExpires(DateTime.Now.AddSeconds(settings.Duration));
                response.Cache.SetMaxAge(new TimeSpan(0, 0, settings.Duration));
            }

            if (settings.NoStore)
            {
                response.Cache.SetNoStore();
            }
        }
Example #2
0
        public string GenerateKey(ControllerContext context, CacheSettings cacheSettings)
        {
            var actionName = context.RouteData.Values["action"].ToString();
            var controllerName = context.RouteData.Values["controller"].ToString();

            // remove controller, action and DictionaryValueProvider which is added by the framework for child actions
            var filteredRouteData = context.RouteData.Values.Where(x => x.Key.ToLowerInvariant() != "controller" &&
                                                                   x.Key.ToLowerInvariant() != "action" &&
                                                                   !(x.Value is DictionaryValueProvider<object>));

            var routeValues = new RouteValueDictionary(filteredRouteData.ToDictionary(x => x.Key.ToLowerInvariant(), x => x.Value));

            if (!context.IsChildAction)
            {
                // note that route values take priority over form values and form values take priority over query string values

                foreach (var formKey in context.HttpContext.Request.Form.AllKeys)
                {
                    if (!routeValues.ContainsKey(formKey.ToLowerInvariant()))
                    {
                        routeValues.Add(formKey.ToLowerInvariant(),
                                        context.HttpContext.Request.Form[formKey].ToLowerInvariant());
                    }
                }

                foreach (var queryStringKey in context.HttpContext.Request.QueryString.AllKeys)
                {
                    // queryStringKey is null if url has qs name without value. e.g. test.com?q
                    if (queryStringKey != null && !routeValues.ContainsKey(queryStringKey.ToLowerInvariant()))
                    {
                        routeValues.Add(queryStringKey.ToLowerInvariant(),
                                        context.HttpContext.Request.QueryString[queryStringKey].ToLowerInvariant());
                    }
                }
            }

            if (!string.IsNullOrEmpty(cacheSettings.VaryByParam))
            {
                if (cacheSettings.VaryByParam.ToLowerInvariant() == "none")
                {
                    routeValues.Clear();
                }
                else if (cacheSettings.VaryByParam != "*")
                {
                    var parameters = cacheSettings.VaryByParam.ToLowerInvariant().Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                    routeValues = new RouteValueDictionary(routeValues.Where(x => parameters.Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value));
                }
            }

            if (!string.IsNullOrEmpty(cacheSettings.VaryByCustom))
            {
                routeValues.Add(cacheSettings.VaryByCustom.ToLowerInvariant(), context.HttpContext.ApplicationInstance.GetVaryByCustomString(HttpContext.Current, cacheSettings.VaryByCustom));
            }

            var key = _keyBuilder.BuildKey(controllerName, actionName, routeValues);

            return key;
        }
        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);

            // 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));
                }
            });
        }
Example #5
0
        public string GenerateKey(ControllerContext context, CacheSettings cacheSettings)
        {
            var routeData = context.RouteData;

            if (routeData == null)
            {
                return(null);
            }

            string actionName     = null,
                   controllerName = null;

            if (
                routeData.Values.ContainsKey(RouteDataKeyAction) &&
                routeData.Values[RouteDataKeyAction] != null)
            {
                actionName = routeData.Values[RouteDataKeyAction].ToString();
            }

            if (
                routeData.Values.ContainsKey(RouteDataKeyController) &&
                routeData.Values[RouteDataKeyController] != null)
            {
                controllerName = routeData.Values[RouteDataKeyController].ToString();
            }

            if (string.IsNullOrEmpty(actionName) || string.IsNullOrEmpty(controllerName))
            {
                return(null);
            }

            string areaName = null;

            if (routeData.DataTokens.ContainsKey(DataTokensKeyArea))
            {
                areaName = routeData.DataTokens[DataTokensKeyArea].ToString();
            }

            // remove controller, action and DictionaryValueProvider which is added by the framework for child actions
            var filteredRouteData = routeData.Values.Where(
                x => x.Key.ToLowerInvariant() != RouteDataKeyController &&
                x.Key.ToLowerInvariant() != RouteDataKeyAction &&
                x.Key.ToLowerInvariant() != DataTokensKeyArea &&
                !(x.Value is DictionaryValueProvider <object>)
                ).ToList();

            if (!string.IsNullOrWhiteSpace(areaName))
            {
                filteredRouteData.Add(new KeyValuePair <string, object>(DataTokensKeyArea, areaName));
            }

            var routeValues = new RouteValueDictionary(filteredRouteData.ToDictionary(x => x.Key.ToLowerInvariant(), x => x.Value));

            if (!context.IsChildAction)
            {
                // note that route values take priority over form values and form values take priority over query string values

                if ((cacheSettings.Options & OutputCacheOptions.IgnoreFormData) != OutputCacheOptions.IgnoreFormData)
                {
                    foreach (var formKey in context.HttpContext.Request.Form.AllKeys)
                    {
                        if (routeValues.ContainsKey(formKey.ToLowerInvariant()))
                        {
                            continue;
                        }

                        var item = context.HttpContext.Request.Form[formKey];
                        routeValues.Add(
                            formKey.ToLowerInvariant(),
                            item != null
                                ? item.ToLowerInvariant()
                                : string.Empty
                            );
                    }
                }

                if ((cacheSettings.Options & OutputCacheOptions.IgnoreQueryString) != OutputCacheOptions.IgnoreQueryString)
                {
                    foreach (var queryStringKey in context.HttpContext.Request.QueryString.AllKeys)
                    {
                        // queryStringKey is null if url has qs name without value. e.g. test.com?q
                        if (queryStringKey == null || routeValues.ContainsKey(queryStringKey.ToLowerInvariant()))
                        {
                            continue;
                        }

                        var item = context.HttpContext.Request.QueryString[queryStringKey];
                        routeValues.Add(
                            queryStringKey.ToLowerInvariant(),
                            item != null
                                ? item.ToLowerInvariant()
                                : string.Empty
                            );
                    }
                }
            }

            if (!string.IsNullOrEmpty(cacheSettings.VaryByParam))
            {
                if (cacheSettings.VaryByParam.ToLowerInvariant() == "none")
                {
                    routeValues.Clear();
                }
                else if (cacheSettings.VaryByParam != "*")
                {
                    var parameters = cacheSettings.VaryByParam.ToLowerInvariant().Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                    routeValues = new RouteValueDictionary(routeValues.Where(x => parameters.Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value));
                }
            }

            if (!string.IsNullOrEmpty(cacheSettings.VaryByCustom))
            {
                // If there is an existing route value with the same key as varybycustom, we should overwrite it
                routeValues[cacheSettings.VaryByCustom.ToLowerInvariant()] =
                    context.HttpContext.ApplicationInstance.GetVaryByCustomString(HttpContext.Current, cacheSettings.VaryByCustom);
            }

            var key = _keyBuilder.BuildKey(controllerName, actionName, routeValues);

            return(key);
        }
        /// <summary>
        /// Builds the cache settings.
        /// </summary>
        /// <returns></returns>
        /// <exception cref="System.Web.HttpException">
        /// The 'duration' attribute must have a value that is greater than or equal to zero.
        /// </exception>
        protected CacheSettings BuildCacheSettings()
        {
            CacheSettings cacheSettings;

            if (string.IsNullOrEmpty(CacheProfile))
            {
                cacheSettings = new CacheSettings
                {
                    IsCachingEnabled = CacheSettingsManager.IsCachingEnabledGlobally,
                    Duration = Duration,
                    VaryByCustom = VaryByCustom,
                    VaryByParam = VaryByParam,
                    Location = (int)Location == -1 ? OutputCacheLocation.Server : Location,
                    NoStore = NoStore,
                    Options = Options,
                };
            }
            else
            {
                var cacheProfile = CacheSettingsManager.RetrieveOutputCacheProfile(CacheProfile);

                cacheSettings = new CacheSettings
                {
                    IsCachingEnabled = CacheSettingsManager.IsCachingEnabledGlobally && cacheProfile.Enabled,
                    Duration = Duration == -1 ? cacheProfile.Duration : Duration,
                    VaryByCustom = VaryByCustom ?? cacheProfile.VaryByCustom,
                    VaryByParam = VaryByParam ?? cacheProfile.VaryByParam,
                    Location = (int)Location == -1 ? ((int)cacheProfile.Location == -1 ? OutputCacheLocation.Server : cacheProfile.Location) : Location,
                    NoStore = _noStore.HasValue ? _noStore.Value : cacheProfile.NoStore,
                    Options = Options,
                };
            }

            if (cacheSettings.Duration == -1)
            {
                throw new HttpException("The directive or the configuration settings profile must specify the 'duration' attribute.");
            }

            if (cacheSettings.Duration < 0)
            {
                throw new HttpException("The 'duration' attribute must have a value that is greater than or equal to zero.");
            }

            return cacheSettings;
        }
        /// <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));
                }
            });
        }
Example #8
0
        public string GenerateKey(ControllerContext context, CacheSettings cacheSettings)
        {
            var routeData = context.RouteData;

            if (routeData == null)
            {
                return(null);
            }

            string actionName     = null,
                   controllerName = null;

            if (
                routeData.Values.ContainsKey(RouteDataKeyAction) &&
                routeData.Values[RouteDataKeyAction] != null)
            {
                actionName = routeData.Values[RouteDataKeyAction].ToString();
            }

            if (
                routeData.Values.ContainsKey(RouteDataKeyController) &&
                routeData.Values[RouteDataKeyController] != null)
            {
                controllerName = routeData.Values[RouteDataKeyController].ToString();
            }

            if (string.IsNullOrEmpty(actionName) || string.IsNullOrEmpty(controllerName))
            {
                return(null);
            }

            string areaName = null;

            if (routeData.DataTokens.ContainsKey(DataTokensKeyArea))
            {
                areaName = routeData.DataTokens[DataTokensKeyArea].ToString();
            }

            // remove controller, action and DictionaryValueProvider which is added by the framework for child actions
            var filteredRouteData = routeData.Values.Where(
                x => !string.Equals(x.Key, RouteDataKeyController, StringComparison.OrdinalIgnoreCase) &&
                !string.Equals(x.Key, RouteDataKeyAction, StringComparison.OrdinalIgnoreCase) &&
                !string.Equals(x.Key, DataTokensKeyArea, StringComparison.OrdinalIgnoreCase) &&
                !(x.Value is DictionaryValueProvider <object>)
                ).ToList();

            if (!string.IsNullOrWhiteSpace(areaName))
            {
                filteredRouteData.Add(new KeyValuePair <string, object>(DataTokensKeyArea, areaName));
            }

            var routeValues = new RouteValueDictionary(filteredRouteData.ToDictionary(x => x.Key, x => x.Value));

            if (!context.IsChildAction)
            {
                // note that route values take priority over form values and form values take priority over query string values

                if ((cacheSettings.Options & OutputCacheOptions.IgnoreFormData) != OutputCacheOptions.IgnoreFormData)
                {
                    foreach (var formKey in context.HttpContext.Request.Form.AllKeys)
                    {
                        if (routeValues.ContainsKey(formKey))
                        {
                            continue;
                        }

                        var item = context.HttpContext.Request.Form[formKey];
                        routeValues.Add(formKey, item ?? string.Empty);
                    }
                }

                if ((cacheSettings.Options & OutputCacheOptions.IgnoreQueryString) != OutputCacheOptions.IgnoreQueryString)
                {
                    foreach (var queryStringKey in context.HttpContext.Request.QueryString.AllKeys)
                    {
                        // queryStringKey is null if url has qs name without value. e.g. test.com?q
                        if (queryStringKey == null || routeValues.ContainsKey(queryStringKey))
                        {
                            continue;
                        }

                        var item = context.HttpContext.Request.QueryString[queryStringKey];
                        routeValues.Add(queryStringKey, item ?? string.Empty);
                    }
                }
            }

            if (!string.IsNullOrEmpty(cacheSettings.VaryByParam))
            {
                if (string.Equals(cacheSettings.VaryByParam, "none", StringComparison.OrdinalIgnoreCase))
                {
                    routeValues.Clear();
                }
                else if (cacheSettings.VaryByParam != "*")
                {
                    var parameters = SplitValues(cacheSettings.VaryByParam)
                                     .Join(routeValues, p => p, rv => rv.Key, (p, rv) => rv, StringComparer.OrdinalIgnoreCase)
                                     .ToDictionary(x => x.Key, x => x.Value);

                    routeValues = new RouteValueDictionary(parameters);
                }
            }

            if (!string.IsNullOrEmpty(cacheSettings.VaryByCustom))
            {
                // If there is an existing route value with the same key as varybycustom, we should overwrite it
                routeValues[cacheSettings.VaryByCustom] = context.HttpContext.ApplicationInstance.GetVaryByCustomString(HttpContext.Current, cacheSettings.VaryByCustom);
            }

            if (!string.IsNullOrEmpty(cacheSettings.VaryByHeader) && !string.Equals(cacheSettings.VaryByHeader, "none", StringComparison.OrdinalIgnoreCase))
            {
                var headers         = context.HttpContext.Request.Headers;
                var headersToVaryBy = cacheSettings.VaryByHeader == "*"
                    ? headers.AllKeys
                    : SplitValues(cacheSettings.VaryByHeader);

                var headersForCaching = headers.AllKeys
                                        .Select(k => new KeyValuePair <string, object>(k, headers.Get(k)))
                                        .Join(headersToVaryBy, kv => kv.Key, h => h, (kv, h) => kv, StringComparer.OrdinalIgnoreCase);

                foreach (var header in headersForCaching)
                {
                    routeValues[header.Key] = header.Value ?? string.Empty;
                }
            }

            var key = _keyBuilder.BuildKey(controllerName, actionName, routeValues);

            return(key);
        }
        public string GenerateKey(ControllerContext context, CacheSettings cacheSettings)
        {
            var routeData = context.RouteData;

            if (routeData == null)
            {
                return null;
            }

            string actionName = null,
                controllerName = null;

            if (
                routeData.Values.ContainsKey(RouteDataKeyAction) &&
                routeData.Values[RouteDataKeyAction] != null)
            {
                actionName = routeData.Values[RouteDataKeyAction].ToString();
            }

            if (
                routeData.Values.ContainsKey(RouteDataKeyController) && 
                routeData.Values[RouteDataKeyController] != null)
            {
                controllerName = routeData.Values[RouteDataKeyController].ToString();
            }

            if (string.IsNullOrEmpty(actionName) || string.IsNullOrEmpty(controllerName))
            {
                return null;
            }

            string areaName = null;

            if (routeData.DataTokens.ContainsKey(DataTokensKeyArea))
            {
                areaName = routeData.DataTokens[DataTokensKeyArea].ToString();
            }

            // remove controller, action and DictionaryValueProvider which is added by the framework for child actions
            var filteredRouteData = routeData.Values.Where(
                x => x.Key.ToLowerInvariant() != RouteDataKeyController && 
                     x.Key.ToLowerInvariant() != RouteDataKeyAction &&   
                     x.Key.ToLowerInvariant() != DataTokensKeyArea &&
                     !(x.Value is DictionaryValueProvider<object>)
            ).ToList();

            if (!string.IsNullOrWhiteSpace(areaName))
            {
                filteredRouteData.Add(new KeyValuePair<string, object>(DataTokensKeyArea, areaName));
            }

            var routeValues = new RouteValueDictionary(filteredRouteData.ToDictionary(x => x.Key.ToLowerInvariant(), x => x.Value));

            if (!context.IsChildAction)
            {
                // note that route values take priority over form values and form values take priority over query string values

                if ((cacheSettings.Options & OutputCacheOptions.IgnoreFormData) != OutputCacheOptions.IgnoreFormData)
                {
                    foreach (var formKey in context.HttpContext.Request.Form.AllKeys)
                    {
                        if (routeValues.ContainsKey(formKey.ToLowerInvariant()))
                        {
                            continue;
                        }

                        var item = context.HttpContext.Request.Form[formKey];
                        routeValues.Add(
                            formKey.ToLowerInvariant(),
                            item != null 
                                ? item.ToLowerInvariant() 
                                : string.Empty
                        );
                    }
                }

                if ((cacheSettings.Options & OutputCacheOptions.IgnoreQueryString) != OutputCacheOptions.IgnoreQueryString)
                {
                    foreach (var queryStringKey in context.HttpContext.Request.QueryString.AllKeys)
                    {
                        // queryStringKey is null if url has qs name without value. e.g. test.com?q
                        if (queryStringKey == null || routeValues.ContainsKey(queryStringKey.ToLowerInvariant()))
                        {
                            continue;
                        }

                        var item = context.HttpContext.Request.QueryString[queryStringKey];
                        routeValues.Add(
                            queryStringKey.ToLowerInvariant(),
                            item != null 
                                ? item.ToLowerInvariant() 
                                : string.Empty
                        );
                    }
                }
            }

            if (!string.IsNullOrEmpty(cacheSettings.VaryByParam))
            {
                if (cacheSettings.VaryByParam.ToLowerInvariant() == "none")
                {
                    routeValues.Clear();
                }
                else if (cacheSettings.VaryByParam != "*")
                {
                    var parameters = cacheSettings.VaryByParam.ToLowerInvariant().Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                    routeValues = new RouteValueDictionary(routeValues.Where(x => parameters.Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value));
                }
            }

            if (!string.IsNullOrEmpty(cacheSettings.VaryByCustom))
            {
                // If there is an existing route value with the same key as varybycustom, we should overwrite it
                routeValues[cacheSettings.VaryByCustom.ToLowerInvariant()] =
                            context.HttpContext.ApplicationInstance.GetVaryByCustomString(HttpContext.Current, cacheSettings.VaryByCustom);
            }

            var key = _keyBuilder.BuildKey(controllerName, actionName, routeValues);

            return key;
        }
Example #10
0
        public string GenerateKey(ControllerContext context, CacheSettings cacheSettings)
        {
            var actionName     = context.RouteData.Values["action"].ToString();
            var controllerName = context.RouteData.Values["controller"].ToString();

            // remove controller, action and DictionaryValueProvider which is added by the framework for child actions
            var filteredRouteData = context.RouteData.Values.Where(
                x => x.Key.ToLowerInvariant() != "controller" &&
                x.Key.ToLowerInvariant() != "action" &&
                !(x.Value is DictionaryValueProvider <object>)
                );

            var routeValues = new RouteValueDictionary(filteredRouteData.ToDictionary(x => x.Key.ToLowerInvariant(), x => x.Value));

            if (!context.IsChildAction)
            {
                // note that route values take priority over form values and form values take priority over query string values

                if ((cacheSettings.Options & OutputCacheOptions.IgnoreFormData) != OutputCacheOptions.IgnoreFormData)
                {
                    foreach (var formKey in context.HttpContext.Request.Form.AllKeys)
                    {
                        if (routeValues.ContainsKey(formKey.ToLowerInvariant()))
                        {
                            continue;
                        }

                        var item = context.HttpContext.Request.Form[formKey];
                        routeValues.Add(
                            formKey.ToLowerInvariant(),
                            item != null
                                ? item.ToLowerInvariant()
                                : string.Empty
                            );
                    }
                }

                if ((cacheSettings.Options & OutputCacheOptions.IgnoreQueryString) != OutputCacheOptions.IgnoreQueryString)
                {
                    foreach (var queryStringKey in context.HttpContext.Request.QueryString.AllKeys)
                    {
                        // queryStringKey is null if url has qs name without value. e.g. test.com?q
                        if (queryStringKey == null || routeValues.ContainsKey(queryStringKey.ToLowerInvariant()))
                        {
                            continue;
                        }

                        var item = context.HttpContext.Request.QueryString[queryStringKey];
                        routeValues.Add(
                            queryStringKey.ToLowerInvariant(),
                            item != null
                                ? item.ToLowerInvariant()
                                : string.Empty
                            );
                    }
                }
            }

            if (!string.IsNullOrEmpty(cacheSettings.VaryByParam))
            {
                if (cacheSettings.VaryByParam.ToLowerInvariant() == "none")
                {
                    routeValues.Clear();
                }
                else if (cacheSettings.VaryByParam != "*")
                {
                    var parameters = cacheSettings.VaryByParam.ToLowerInvariant().Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                    routeValues = new RouteValueDictionary(routeValues.Where(x => parameters.Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value));
                }
            }

            if (!string.IsNullOrEmpty(cacheSettings.VaryByCustom))
            {
                routeValues.Add(
                    cacheSettings.VaryByCustom.ToLowerInvariant(),
                    context.HttpContext.ApplicationInstance.GetVaryByCustomString(HttpContext.Current, cacheSettings.VaryByCustom)
                    );
            }

            var key = _keyBuilder.BuildKey(controllerName, actionName, routeValues);

            return(key);
        }