将Response.Cache._cacheability设置为NoCache后更改

时间:2012-09-13 20:35:18

标签: c# asp.net caching

似乎,一旦您将Response.Cache的可缓存性设置为NoCache,就无法再次更改它。以下是该问题的简单但完整的说明:

protected void Page_Load(object sender, EventArgs e)
{
    FieldInfo fi = typeof(HttpCachePolicy).GetField(
        "_cacheability",
        BindingFlags.NonPublic | BindingFlags.Instance);

    // Default value = 6
    HttpCacheability first = (HttpCacheability)fi.GetValue(Response.Cache);

    // Can change it to Public
    Response.Cache.SetCacheability(HttpCacheability.Public);
    HttpCacheability second = (HttpCacheability)fi.GetValue(Response.Cache);

    // Can change it to Private
    Response.Cache.SetCacheability(HttpCacheability.Private);
    HttpCacheability third = (HttpCacheability)fi.GetValue(Response.Cache);

    // Can change it to NoCache
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    HttpCacheability fourth = (HttpCacheability)fi.GetValue(Response.Cache);

    // Can't go back to Private!  Stuck on NoCache
    Response.Cache.SetCacheability(HttpCacheability.Private);
    HttpCacheability fifth = (HttpCacheability)fi.GetValue(Response.Cache);
}

我错过了什么吗?有没有办法做到这一点?

编辑:当然,如果我使用Reflection进行设置,它会起作用,但我担心当你设置为HttpCacheability.NoCache时会发生其他事情,如果我去的话我会想念的在幕后..并且更愿意以官方支持的方式进行。

EDIT2: Private似乎也发生了同样的事情;你能加强限制吗?

protected void Page_Load(object sender, EventArgs e)
{
    FieldInfo fi = typeof(HttpCachePolicy).GetField(
        "_cacheability",
        BindingFlags.NonPublic | BindingFlags.Instance);

    // Default value = 6
    HttpCacheability first = (HttpCacheability)fi.GetValue(Response.Cache);

    // Can change it to Private
    Response.Cache.SetCacheability(HttpCacheability.Private);
    HttpCacheability second = (HttpCacheability)fi.GetValue(Response.Cache);

    // Can't change to Public!  Stuck on Private
    Response.Cache.SetCacheability(HttpCacheability.Public);
    HttpCacheability third = (HttpCacheability)fi.GetValue(Response.Cache);

    // Can change to NoCache - Can only go more restrictive?
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    HttpCacheability fourth = (HttpCacheability)fi.GetValue(Response.Cache);
}

2 个答案:

答案 0 :(得分:1)

破解打开的Reflector,看看HttpCachePolicy

public void SetCacheability(HttpCacheability cacheability)
{
    if ((cacheability < HttpCacheability.NoCache) || (HttpCacheability.ServerAndPrivate < cacheability))
    {
        throw new ArgumentOutOfRangeException("cacheability");
    }
    if (s_cacheabilityValues[(int) cacheability] < s_cacheabilityValues[(int) this._cacheability])
    {
        this.Dirtied();
        this._cacheability = cacheability;
    }
}

s_cacheabilityValues在静态构造函数中设置:

s_cacheabilityValues = new int[] { -1, 0, 2, 1, 4, 3, 100 };

Dirtied()被调用,但它似乎只是设置了一些标志:

private void Dirtied()
{
    this._isModified = true;
    this._useCachedHeaders = false;
}

它确实看起来有更改值的规则,但看起来它们没有太大的影响。因此,使用反射改变可能是安全的。

fi.SetValue(Response.Cache, HttpCacheability.Private);

答案 1 :(得分:0)

事实上,似乎反思是唯一安全的方式。深入研究代码,您需要从Response的Cache属性中提取HttpCachePolicy类型的对象,如下所示:

 public class HttpCachePolicyWrapper : HttpCachePolicyBase
{
    private HttpCachePolicy _httpCachePolicy;
    ....
}

为此,只需使用反射来设置Response.Cache对象中正确对象的值,如下面的代码所示:

FieldInfo fi = typeof(HttpCachePolicy).GetField("_cacheability", BindingFlags.NonPublic | BindingFlags.Instance);
var objectToChange = (HttpCachePolicy)context.Response.Cache.GetType().GetField("_httpCachePolicy", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(context.Response.Cache);
fi.SetValue(objectToChange, HttpCacheability.Public);

这只是为zimdanen的答案添加了更多的完整步骤