gpt4 book ai didi

c# - OutputCache VaryByCustom cookie 值

转载 作者:太空狗 更新时间:2023-10-29 19:42:13 26 4
gpt4 key购买 nike

有没有办法根据 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

If a given HttpResponse contains one or more outbound cookies with Shareable is set to false (the default value), output caching will be suppressed for the response. This prevents cookies that contain potentially sensitive information from being cached in the response and sent to multiple clients. To allow a response containing cookies to be cached, configure caching normally for the response, such as using the OutputCache directive or MVC's [OutputCache] attribute, and set all outbound cookies to have Shareable set to true.

最佳答案

微妙的答案是否定的。

解释答案如下:

输出缓存不能很好地处理 cookie 的原因

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

解决方案:

虽然有一些解决方法,输出缓存将响应 header 和内容缓存在一起,并且在将它们发送回用户之前不提供任何 Hook 来修改它们。但是,有一种方法可以提供在之前更改的能力在将响应的 header 发送回用户之前缓存响应的 header 。其中之一需要 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")
});
};

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

关于c# - OutputCache VaryByCustom cookie 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45988628/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com