c# – 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); } 我可以验证我的浏览器是否有ztest cookie,但是当我调试Index方法时,我每次都会遇到断点(意味着缓存不起作用). HttpResponse没有出站cookie,所以这一点不适用:https://msdn.microsoft.com/en-us/library/system.web.httpcookie.shareable(v=vs.110).aspx
解决方法
微妙的答案是否定的.
解释的答案如下: 输出缓存与cookie不兼容的原因 因此,输出缓存不会使用cookie缓存响应的原因是cookie可能是用户特定的(例如,身份验证,分析跟踪等).如果一个或多个具有属性HttpCookie.Shareable = false的cookie,则输出缓存会认为响应不可缓存. 解: 但是有一些解决方法,输出缓存将响应头和内容缓存在一起,并且在将它们发送回用户之前不提供任何钩子来修改它们.但是,有一种方法可以在缓存响应的头之前提供更改在它们被发回给用户之前. 我有一个代码示例: 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(int),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,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",toClone.GetFieldValue("_kernelCacheUrl",toClone.GetFieldValue("_dependenciesKey",toClone.GetFieldValue("_dependencies",toClone.GetFieldValue("_statusCode",toClone.GetFieldValue("_statusDescription",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") }); }; 我不知道它是否回答了你的问题,但我希望它指向正确的方向. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |