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