以编程方式控制输出缓存 - 根据参数值禁用或启用缓存
Posted
技术标签:
【中文标题】以编程方式控制输出缓存 - 根据参数值禁用或启用缓存【英文标题】:programmatically control output caching - disable or enable cache according to parameter value 【发布时间】:2010-11-05 19:11:19 【问题描述】:我们有一个相当标准的电子商务场景,其中包含分类中的产品分页列表。无论好坏,大约 80% 的访问者从未浏览过第一页,根据类别的不同,可能会有 5 到 10 多页的结果被查看的频率要低得多。 (是的,我们确实优化了第一页上显示的内容并进行了良好的搜索 - 但这是一个不同的讨论)
我们不能缓存每一页结果,因为我们受到内存的限制,但是只缓存每个类别的第一页结果的好处是巨大的。
我知道我可以使用对象缓存来存储有问题的数据集来做类似的事情,但这是否可以使用输出缓存,也许通过使用 response.Cache 对象?
这可以在页面生命周期的哪个位置完成?预渲染?
非常简化,URL 类似于“/ProductList?Category=something&Page=1” 我想要类似(伪代码)的逻辑:
If paramater "Page" equals 1
Use output caching: vary by param = "categoryName; page"
else
Don't use caching at all, just render the page from scratch.
我们在 IIS 6/win2003 上使用 ASP.NET 2.0。
【问题讨论】:
查看this 帖子上的最后一个答案。我希望这会有所帮助。 【参考方案1】:您仍然可以使用 outputcache 指令,在我看来,与其在页面代码中乱扔一堆缓存细节,不如使用基于 Global.asax 中处理此问题的可重用解决方案您通常会采用任何 VaryByCustom 场景的方式。
因此,例如,如果您使用带有转发器的分页方法,您可能只是在搜索场景中希望从缓存中排除特定页面上的任何回发。 Here 是一个这样做的代码示例。该方法只需要在捕获您希望避免缓存的任何标准之后使用 HttpContext 对象来访问 Response.Cache.SetNoServerCaching()。我希望这会有所帮助。
【讨论】:
【参考方案2】:我相信最好的方法是使用HttpCachePolicy.AddValidationCallback
见http://www.hanselman.com/blog/AdvancedASPNETCachingAndAddValidationCallBack.aspx - 有一个完整的例子可以准确回答这个问题。
【讨论】:
【参考方案3】:除了使用 OutputCache 指令,您还可以通过编程执行相同的操作,如下所示:
if (yourArbitraryCondition)
OutputCacheParameters outputCacheSettings = new OutputCacheParameters();
outputCacheSettings.Duration = 60;
InitOutputCache(outputCacheSettings);
从 OnInit 执行此操作应该可以正常工作。显然,您可以通过设置 OutputCacheParameter 上的各种属性来调整缓存行为,它与指令具有所有相同的旋钮(实际上,这就是我们在使用指令时生成的)。
关键是你只是有条件地执行这个逻辑,而指令使它成为无条件的。
更新:
作为替代方案,您可以使用构建上述代码的低级缓存 API。例如
HttpCachePolicy cache = Response.Cache;
cache.SetCacheability(HttpCacheability.Public);
cache.SetExpires(Context.Timestamp.AddSeconds(60));
cache.VaryByParams["categoryName"] = true;
基本上,这是做同样事情的另一种方式,不使用任何标记为“不应调用”的 API。最后,任何一种方式都行得通,所以选择吧。
【讨论】:
有效。知道为什么InitOutputCache
是EditorBrowsableState.Never
并且不应该根据msdn.microsoft.com/en-us/library/ms153473.aspx 直接调用吗?
嗯,这主要是因为我们最初设计它时缺乏前瞻性思维。页面上有许多以这种方式标记的公共/受保护的 API。它们都是由于使用各种语法而被生成的代码调用的东西,我们认为用户没有任何充分的理由直接调用它们。但现实情况是,自己调用它们并没有错,事实上,有时像这里一样,它可以让你做一些你不能用页面语法做的事情。我将提交一个错误以删除这些标志,尽管对于 VS2010 来说已经太晚了。
还有一件事:您实际上可以通过直接调用低级缓存 API 来做同样的事情(并避免 InitOutputCache)。它的工作原理相同,但代码会更复杂。如果您需要替代解决方案,请告诉我。
这可以与片段缓存一起使用以缓存动态生成的单个控件吗?换句话说,如果一个动态控件随一个参数变化,另一个动态控件随另一个参数变化呢?
如果不包含 outputCacheSettings.VaryByParam = "none";【参考方案4】:
编辑: 我更喜欢 David Ebbo 的回答。
你可以使用
<%@ OutputCache Duration="60" VaryByParam="none" VaryByCustom="pageOne" %>
并以返回第一页的固定键和所有其他页面的随机键的方式实现它。您可以(并且应该)让scavenging 机制处理内存,但如果必须,您可以使用HttpResponse.RemoveOutputCacheItem
删除缓存项。
public override string GetVaryByCustomString(HttpContext ctx, string custom)
if(custom == "pageOne")
if(ctx.Request["page"] == "1")
return "1";
HttpResponse.RemoveOutputCacheItem("/Default.aspx");
return Guid.NewGuid().ToString();
return base.GetVaryByCustomString(ctx, custom);
【讨论】:
【参考方案5】:我认为您应该能够使用 OutputCache directive 并将 VaryByParam 属性设置为用于改变输出缓存的分号分隔的字符串列表。
除非您只想在 Page == 1 时仅缓存?
【讨论】:
不幸的是,这正是我想要的(仅当 page == 1 时)。如果我想缓存每一页很容易的结果,就像你说的那样使用varybyparam。抱歉,我认为我没有很清楚地表达这个问题,但我所追求的只是与每个人习惯的正常情况略有不同(但显着)。以上是关于以编程方式控制输出缓存 - 根据参数值禁用或启用缓存的主要内容,如果未能解决你的问题,请参考以下文章
Android:如何以编程方式启用/禁用 Wifi 或 Internet 连接