在对这个问题进行了一点研究之后,我开始了解和解决这个问题。
原因输出缓存没有发挥好与cookies
所以输出缓存将不缓存与cookies响应的原因是,一个cookie可以是用户特定的(例如身份验证,分析跟踪,等等。)。如果一个或多个cookie属性为HttpCookie.Shareable = false
,则输出缓存会将响应视为不可缓存。
包括与缓存的响应
这是它获得的棘手饼干。输出缓存将响应标头和内容缓存在一起,并且在将它们发送回用户之前不提供任何钩子来修改它们。 不过,我写了下面的自定义输出缓存提供提供修改缓存响应头的能力,他们在发送之前返回给用户(要求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")
});
};
你有没有前夕r找到了解决办法? – Allov 2012-03-21 13:52:37
我发现同样的事情是真实的,但没有遇到任何官方文档。明确声明它不起作用。 – JNappi 2012-04-16 16:07:21
@Allov,对于延迟抱歉 - 不,我没有解决方案。除了摆脱cookie或如果我需要一个cookie,我可以在刚刚设置cookie的页面上添加脚本标记或0x0图像。 – 2012-04-17 08:50:57