OutputCache VaryByCustom cookie值

有没有办法根据cookie值设置OutputCache的值?

为了简单起见,这是我的方法

[OutputCache(Duration = 600, VaryByParam = "None", VaryByCustom = "ztest")] public ViewResult Index() { return View(); } 

我的Global.asax有这个(为了覆盖GetVaryByCustomString方法

 public override string GetVaryByCustomString(HttpContext context, string custom) { if (custom == "ztest") { HttpCookie ztest = context.Request.Cookies["ztest"]; if (ztest != null) { return ztest.Value; } } return base.GetVaryByCustomString(context, custom); } 

我可以validation我的浏览器是否有ztest cookie,但是当我调试Index方法时,我每次都会遇到断点(意味着缓存不起作用)。

HttpResponse没有出站cookie,所以这一点不适用: https : //msdn.microsoft.com/en-us/library/system.web.httpcookie.shareable(v=vs.110).aspx

如果给定的HttpResponse包含一个或多个出站cookie,并且Shareable设置为false(默认值),则将抑制响应的输出缓存。 这可以防止包含潜在敏感信息的cookie缓存在响应中并发送到多个客户端。 要允许缓存包含cookie的响应,请为响应正常配置缓存,例如使用OutputCache指令或MVC的[OutputCache]属性,并设置所有出站cookie以使Shareable设置为true。

微妙的答案是否定的。

解释的答案如下:

输出缓存与cookie不兼容的原因

因此,输出缓存不会使用cookie缓存响应的原因是cookie可能是特定于用户的(例如,身份validation,分析跟踪等)。 如果一个或多个具有属性HttpCookie.Shareable = false cookie,则输出缓存会认为响应不可缓存。

解:

但是有一些解决方法,输出缓存将响应头和内容缓存在一起,并且在将它们发送回用户之前不提供任何钩子来修改它们。但是,有一种方法可以在缓存响应的头之前提供更改在它们被发回给用户之前。 其中一个需要Fasterflect nuget包

我有一个代码示例:

 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Caching; using System.Web; using System.Web.Caching; using Fasterflect; namespace CustomOutputCache { ///  /// An output cache provider that has ability to modify the http header collection before a cached response is served back to the user. ///  public class HeaderModOutputCacheProvider : OutputCacheProvider { private static readonly Type OutputCacheEntryType, HttpCachePolicySettingsType; private static readonly Type[] ParameterTypes; public static event EventHandler RequestServedFromCache; static HeaderModOutputCacheProvider() { var systemWeb = typeof(HttpContext).Assembly; OutputCacheEntryType = systemWeb.GetType("System.Web.Caching.OutputCacheEntry"); HttpCachePolicySettingsType = systemWeb.GetType("System.Web.HttpCachePolicySettings"); ParameterTypes = new[]{ typeof(Guid), HttpCachePolicySettingsType, typeof(string), typeof(string) , typeof(string[]), typeof(int), typeof(string), typeof(List), typeof(List) }; } private readonly ObjectCache _objectCache; public HeaderModOutputCacheProvider() { _objectCache = new MemoryCache("output-cache"); } #region OutputCacheProvider implementation public override object Get(string key) { var cachedValue = _objectCache.Get(key); if (cachedValue == null) return null; if (cachedValue.GetType() != OutputCacheEntryType) return cachedValue; var cloned = CloneOutputCacheEntry(cachedValue); if (RequestServedFromCache != null) { var args = new CachedRequestEventArgs(cloned.HeaderElements); RequestServedFromCache(this, args); } return cloned; } public override object Add(string key, object entry, DateTime utcExpiry) { _objectCache.Set(key, entry, new CacheItemPolicy { AbsoluteExpiration = utcExpiry }); return entry; } public override void Set(string key, object entry, DateTime utcExpiry) { _objectCache.Set(key, entry, new CacheItemPolicy { AbsoluteExpiration = utcExpiry }); } public override void Remove(string key) { _objectCache.Remove(key); } #endregion private IOutputCacheEntry CloneOutputCacheEntry(object toClone) { var parameterValues = new[] { toClone.GetFieldValue("_cachedVaryId", Flags.InstancePrivate), toClone.GetFieldValue("_settings", Flags.InstancePrivate), toClone.GetFieldValue("_kernelCacheUrl", Flags.InstancePrivate), toClone.GetFieldValue("_dependenciesKey", Flags.InstancePrivate), toClone.GetFieldValue("_dependencies", Flags.InstancePrivate), toClone.GetFieldValue("_statusCode", Flags.InstancePrivate), toClone.GetFieldValue("_statusDescription", Flags.InstancePrivate), CloneHeaders((List)toClone.GetFieldValue("_headerElements", Flags.InstancePrivate)), toClone.GetFieldValue("_responseElements", Flags.InstancePrivate) }; return (IOutputCacheEntry)OutputCacheEntryType.CreateInstance( parameterTypes: ParameterTypes, parameters: parameterValues ); } private List CloneHeaders(List toClone) { return new List(toClone); } } public class CachedRequestEventArgs : EventArgs { public CachedRequestEventArgs(List headers) { Headers = headers; } public List Headers { get; private set; } public void AddCookies(HttpCookieCollection cookies) { foreach (var cookie in cookies.AllKeys.Select(c => cookies[c])) { //more reflection unpleasantness :( var header = cookie.CallMethod("GetSetCookieHeader", Flags.InstanceAnyVisibility, HttpContext.Current); Headers.Add(new HeaderElement((string)header.GetPropertyValue("Name"), (string)header.GetPropertyValue("Value"))); } } } } 

以这种方式连线:

          

并以这种方式使用它:

 HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache; HeaderModOutputCacheProvider.RequestServedFromCache += (sender, e) => { e.AddCookies(new HttpCookieCollection { new HttpCookie("key", "value") }); }; 

我不知道它是否回答了你的问题,但我希望它指向正确的方向。