OutputCache VaryByCustom cookie值

问题描述:

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

对于纯朴的缘故,这是我的方法

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

我可以确认我的浏览器有ztest cookie,但是当我调试Index方法时,我每次都会触发断点(意思是缓存不起作用)

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

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

+0

你试过检查'HttpCookie.Shareable = true'吗? ,在你的情况下,它会像'cookie。可共享= true; ' – Webruster

+0

您的意思是检查'GetVaryByCustomString'方法中的Shareable值是否为真? – Zac

+0

首先检查通常默认情况下它会'false',尝试更改为'true' – Webruster

微妙的答案是否定的。

的解释答案如下:

原因输出缓存没有发挥好与cookies

所以输出缓存将不缓存与cookies响应的原因是,一个cookie可能是用户特定的(例如认证,分析跟踪等)。如果一个或多个cookie属性为HttpCookie.Shareable = false,则输出缓存会将响应视为不可缓存。

解决方案:

有一些变通办法虽然,输出缓存缓存响应头和内容一起,并且不提供任何钩子把他们回user.However之前修改这些,还有一种提供在缓存响应标题发送回用户之前进行更改的功能的方法。 其中之一需要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 
{ 
    /// <summary> 
    /// An output cache provider that has ability to modify the http header collection before a cached response is served back to the user. 
    /// </summary> 
    public class HeaderModOutputCacheProvider : OutputCacheProvider 
    { 
     private static readonly Type OutputCacheEntryType, HttpCachePolicySettingsType; 
     private static readonly Type[] ParameterTypes; 

     public static event EventHandler<CachedRequestEventArgs> 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<HeaderElement>), 
       typeof(List<ResponseElement>) 
      }; 
     } 

     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<HeaderElement>)toClone.GetFieldValue("_headerElements", Flags.InstancePrivate)), 
       toClone.GetFieldValue("_responseElements", Flags.InstancePrivate) 
      }; 

      return (IOutputCacheEntry)OutputCacheEntryType.CreateInstance(
       parameterTypes: ParameterTypes, 
       parameters: parameterValues 
      ); 
     } 

     private List<HeaderElement> CloneHeaders(List<HeaderElement> toClone) 
     { 
      return new List<HeaderElement>(toClone); 
     } 
    } 

    public class CachedRequestEventArgs : EventArgs 
    { 
     public CachedRequestEventArgs(List<HeaderElement> headers) 
     { 
      Headers = headers; 
     } 
     public List<HeaderElement> 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"))); 
      } 
     } 
    } 
} 

电线它是这样的:

<system.web> 
    <caching> 
     <outputCache defaultProvider="HeaderModOutputCacheProvider"> 
     <providers> 
      <add name="HeaderModOutputCacheProvider" type="CustomOutputCache.HeaderModOutputCacheProvider"/> 
     </providers> 
     </outputCache> 
    </caching> 
    </system.web> 

而且使用这种方式:

HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache; 

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

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

+0

我没有最终使用您的解决方案,而是最终从取决于cookie值的代码中移除了'OutputCache' – Zac