简体   繁体   English

以编程方式控制输出缓存 - 根据参数值禁用或启用缓存

[英]programmatically control output caching - disable or enable cache according to parameter value

We've got a fairly standard e-commerce scenario with paged lists of products within categories. 我们有一个相当标准的电子商务场景,其中包含类别中的产品分页列表。 For better or worse, about 80% of visitors never navigate past the first page, depending on the category there may then be 5-10 more pages of results which are viewed far less often. 无论好坏,大约80%的访问者从未浏览过第一页,根据类别,可能会有5-10多个结果页面,这些页面的查看次数要少得多。 (Yes we do optimise what appears on the first page and have good search - but that's a different discussion) (是的,我们会优化第一页上显示的内容并进行良好的搜索 - 但这是一个不同的讨论)

We can't cache every single page of results, because we're constrained by memory, but the benefit of caching just the first page of results for each category would be huge. 我们无法缓存每一页的结果,因为我们受到内存的限制,但是缓存每个类别的第一页结果的好处将是巨大的。

I know I could do something similar using object caching to store the datasets in question, but is this possible using output caching, perhaps by using the response.Cache object? 我知道我可以使用对象缓存来存储有问题的数据集,但这可能是使用输出缓存,也许是通过使用response.Cache对象?

Where in the page lifecycle could this be done? 页面生命周期中的哪个位置可以完成? Pre-render? 预渲染?

Much simplified, the URL is something like "/ProductList?Category=something&Page=1" And I'd want logic something like (pseudocode): 很简单,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.

We're using ASP.NET 2.0, on IIS 6/win2003. 我们在IIS 6 / win2003上使用ASP.NET 2.0。

Instead of using the OutputCache directive, you can do the same thing programmatically, as follows: 您可以通过编程方式执行相同的操作,而不是使用OutputCache指令,如下所示:

if (yourArbitraryCondition) {
  OutputCacheParameters outputCacheSettings = new OutputCacheParameters();
  outputCacheSettings.Duration = 60;
  InitOutputCache(outputCacheSettings);
}

Doing this from OnInit should work fine. 从OnInit执行此操作应该可以正常工作。 And obviously, you can tweak the caching behavior by setting the various properties on the OutputCacheParameter, which has all the same knobs as the directive (in fact, that's what we generate when you use the directive). 显然,您可以通过在OutputCacheParameter上设置各种属性来调整缓存行为,OutputCacheParameter具有与指令相同的旋钮(事实上,这是我们在使用指令时生成的)。

The key point is that you're only executing this logic conditionally, while the directive makes it unconditional. 关键是你只是有条件地执行这个逻辑,而指令使它无条件。

UPDATE: 更新:

As an alternative, you can use the low level cache API that the code above is built on. 作为替代方案,您可以使用上面代码构建的低级缓存API。 eg 例如

HttpCachePolicy cache = Response.Cache;
cache.SetCacheability(HttpCacheability.Public);
cache.SetExpires(Context.Timestamp.AddSeconds(60));
cache.VaryByParams["categoryName"] = true;

Basically, it's another way of doing the same thing, without using any API's marked as 'should not be called'. 基本上,这是做同样事情的另一种方式,不使用任何标记为“不应该被调用”的API。 In the end, either way will work, so take your pick. 最后,无论哪种方式都有效,请选择。

edit: I like David Ebbo's answer a lot better than my own. 编辑: 我比David Ebbo的回答要好得多。


You could use 你可以用

<%@ OutputCache Duration="60"  VaryByParam="none" VaryByCustom="pageOne" %>

and implement it in a way that returns a fixed key for the first page and a random key for all other pages. 并以一种方式实现它,返回第一页的固定键和所有其他页的随机键。 You can (and should ) let the scavenging mechanism take care of memory but you can use HttpResponse.RemoveOutputCacheItem to remove cache items if you must. 您可以(并且应该 )让清理机制处理内存,但如果必须,可以使用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);
}

I believe the best way to do this is to use HttpCachePolicy.AddValidationCallback 我相信最好的方法是使用HttpCachePolicy.AddValidationCallback

See http://www.hanselman.com/blog/AdvancedASPNETCachingAndAddValidationCallBack.aspx - There's a full example that answers precisely this question. 请参阅http://www.hanselman.com/blog/AdvancedASPNETCachingAndAddValidationCallBack.aspx - 这是一个完整的例子,可以准确回答这个问题。

You can still use the outputcache directive, and in my opinion, rather than litter your page code with a bunch of caching nuts and bolts, you're better off going with a reusable solution based on handling this in Global.asax the way you normally would any VaryByCustom scenario. 您仍然可以使用outputcache指令,在我看来,不是通过一堆缓存螺母和螺栓丢弃您的页面代码,您最好使用基于在Global.asax中以正常方式处理此问题的可重用解决方案任何VaryByCustom情况。

So, for example, if you are using a paging approach with a repeater, you might simply in your search scenario want to exclude any postback on a particular page from the cache. 因此,例如,如果您使用转发器的分页方法,您可能只是在搜索方案中想要从缓存中排除特定页面上的任何回发。 Here is a code example that does just that. 是一个代码示例。 The approach merely requires using the HttpContext object to access Response.Cache.SetNoServerCaching(), after trapping whatever criteria for which you wish to avoid caching. 在捕获您希望避免缓存的任何条件之后,该方法仅需要使用HttpContext对象来访问Response.Cache.SetNoServerCaching()。 I hope this helps. 我希望这有帮助。

I think you should be able to use the OutputCache directive with the VaryByParam property set to a semi-colon separated list of strings used to vary the output cache. 我认为您应该能够使用OutputCache指令将VaryByParam属性设置为用于改变输出缓存的以分号分隔的字符串列表。

Unless you were wanting to just cache only when Page == 1? 除非你只想在Page == 1 时才缓存?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM