WebMethod] [ScriptMethod(UseHttpGet = true)] public DateTime GetServerTime() { HttpCachePolicy cache = HttpContext.Current.Response.Cache; cache.SetCacheability(HttpCacheability.Private); cache.SetExpires(DateTime.Now.AddSeconds((double)10)); cache.SetMaxAge(new TimeSpan(0, 0, 10)); return DateTime.Now; } |
我们将Cacheability设为Public(Private也是可以的,如果您希望Response只为同一个客户端缓存,而不能在多个客户端共享。自然这是为有中间结点的情况服务的,例如通过代理服务器请求资源),并且指定了一个10秒钟的过期时间。我们同样调用了SetMaxAge方法将max-age的值设为10秒钟,因为ASP.NET AJAX在这之前已经将它设为了零(TimeSpan.Zero)。让我们来看一下效果……缓存失败?我们随意挑一个Response查看一下它的Header。
Cache-Control public, max-age=0 Date Fri, 29 Jun 2007 00:44:14 GMT Expires Fri, 29 Jun 2007 00:44:24 GMT |
问题就在于Cache-Control中的max-age的值被设为了0。我们已经将其设为了10秒但是它依旧是零的原因则在于HttpCachePolicy中SetMaxAge方法的实现上:
public void SetMaxAge(TimeSpan delta) { if (delta < TimeSpan.Zero) { throw new ArgumentOutOfRangeException("delta"); } if (s_oneYear < delta) { delta = s_oneYear; } if (!this._isMaxAgeSet || (delta < this._maxAge)) { this.Dirtied(); this._maxAge = delta; this._isMaxAgeSet = true; } } |
一旦我们调用了SetMaxAge方法之后,_isMaxAgeSet标记就被设为了true,它组织_maxAge变量被设为比当前小的值。当我们在执行Script Method时,_isMaxAgeSet标记已经是true,并且_maxAge变量的值为Time.Zero,因此我们已经不能将其改变成其它的值了(Omar大牛在之前的某篇文章中认为不能改变max-age是因为ASP.NET 2.0的Bug,其实并非这样)。到了使用反射机制的时候了。我们要做的就是直接改变_maxAge变量的值。
[WebMethod] [ScriptMethod(UseHttpGet = true)] public DateTime GetServerTime() { HttpCachePolicy cache = HttpContext.Current.Response.Cache; cache.SetCacheability(HttpCacheability.Private); cache.SetExpires(DateTime.Now.AddSeconds((double)10)); FieldInfo maxAgeField = cache.GetType().GetField( "_maxAge", BindingFlags.Instance | BindingFlags.NonPublic); maxAgeField.SetValue(cache, new TimeSpan(0, 0, 10)); return DateTime.Now; } |
我们检验一下缓存的效果:
似乎和之前没有什么两样,但是HttpWatch能够告诉我们个中区别: