我的ASP.NET MVC网站缓存无法正常工作?

5

我正在尝试在我的ASP.NET MVC网站中使用OutputCaching。问题是,当我尝试更改其中一个查询字符串参数的值时,它返回了请求的第一个项目的数据!

以下是我的代码(已更改参数名称)...

[ApiAuthorize]
[HandleErrorAsJson]
public class SearchController : Controller
{
    [AcceptVerbs(HttpVerbs.Get)]
    [OutputCache(Duration = 60, VaryByParam = "*")]
    public ActionResult ScoreCard(string foo, byte? bar, byte? pewpew)
    {
    ..
    }
}
  • 注意1:ApiAuthorize --自定义属性,检查查询字符串参数是否为“Key”,并检查内存字典是否存在。
  • 注意2:HandleErrorAsJson --自定义属性,如果抛出异常,则将错误消息返回为json格式。

以下是我对此操作进行的两个示例调用:

因此,第一个调用(foo = hello world, Pew Pew)的数据将作为200 OK返回。 然后第二个api调用返回一个200 OK,但其中包含了先前调用的数据。

另外,我没有使用任何代理服务器。 如果我注释掉OutputCache属性,一切都很好。

我还尝试了手动列出每次需要缓存的列表...

[OutputCache(Duration = 60, VaryByParam = "foo,key,bar,pewpew")]

没那么幸运 :(

请注意,我需要确保将API“Key”参数作为缓存唯一键的一部分包括在内。我不希望别人搜索同样的内容,但如果第二个人没有正确的密钥,则不应该得到缓存结果,而是一个错误消息(技术上来说,它是401未经授权,但无论如何)...

您有什么想法?

2个回答

4
在VaryByParam中,参数列表应该是用分号分隔的,而不是逗号分隔的。试试这个方法。话虽如此,星号应该也能工作。

+1 更直接地关注问题。虽然我认为这不是他在这里唯一的问题。我也回复了你下面的评论。 - dove

0

我使用一个输出缓存过滤器,它可以在编程时进行控制以进行调试,并且可以设置何时需要进行缓存。请随意使用它并查看是否在此处设置会产生差异,我认为这可能会有所帮助(还要确保清除任何先前的缓存)。

public class CacheFilterAttribute : ActionFilterAttribute
    {
        private const int Second = 1;
        private const int Minute = 60 * Second;
        private const int Hour = 60 * Minute;
        public const int SecondsInDay = Hour * 24;


        /// <summary>
        /// Gets or sets the cache duration in seconds. The default is 10 seconds.
        /// </summary>
        /// <value>The cache duration in seconds.</value>
        public int Duration
        {
            get;
            set;
        }

        public int DurationInDays
        {
            get { return Duration / SecondsInDay; }
            set { Duration = value * SecondsInDay; }
        }

        public CacheFilterAttribute()
        {
            Duration = 10;
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (Duration <= 0) return;

            HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
            TimeSpan cacheDuration = TimeSpan.FromSeconds(Duration);

            cache.SetCacheability(HttpCacheability.Public);
            cache.SetExpires(DateTime.Now.Add(cacheDuration));
            cache.SetMaxAge(cacheDuration);
            cache.AppendCacheExtension("must-revalidate, proxy-revalidate");
        }
    }

到目前为止,我只是在网站的一个非常静态的部分使用它,因此有像这样的调用

[CacheFilter(DurationInDays = 1)]

显然,您只想将其扩展为具有VaryByParams公开属性,可以提供但听起来您知道该怎么做。


出于好奇,你为什么最终在这里创建了自己的属性? - Pure.Krome
我已经在几个视图上应用了它,还会继续使用。虽然我并没有对以上确切设置百分百确定,但通过这种方法,我可以轻松调整并知道它已经应用到每个地方。我仍然不确定在设置缓存时是否需要添加更多标头。当然,如果我发现这是一个坏主意,我可以将其作为OutputCache属性的清晰扩展,并不会失去任何东西。所以简而言之,通过一个明确的安全路径,我得到了一些收益,如果出现任何风险,也可以保持安全。 - dove
他所做的没有问题,但这并没有回答你的问题。他创建的过滤器影响的是 浏览器 缓存,而不是服务器缓存。这样做是合法的,我也不知道 ASP.NET MVC 中是否有任何内置的方法可以实现这一点。它还隐含地指出了一个很好的观点,即这里涉及到两个不同的缓存,一个是浏览器的缓存,另一个是服务器的缓存。你的问题在我看来似乎与服务器缓存有关,不过最好用 Firebug 或 Fiddler 再进行一次双重检查。 - Craig Stuntz
1
@Craig 谢谢您指出这一点,我原以为 HttpCacheability.Public 包含 Server 但你是对的。看起来不可能完全选择。也就是说,你可以设置 HttpCacheability.ServerAndPrivate 但这会排除代理(ISPs),而我绝对希望使用代理。但是,上面的确在服务器上缓存了,感谢 AppendCacheExtension("must-revalidate, proxy-revalidate"); 添加后我已经确认过了,所以它是服务器缓存,虽然表达不够完美,有可能出现问题。 - dove
1
AppendCacheExtension只做一件事:将文本添加到HTTP响应的标头中。请参阅http://msdn.microsoft.com/en-us/library/system.web.httpcachepolicy.appendcacheextension.aspx。它将文本添加到响应而不是请求,这告诉您它影响的内容。 - Craig Stuntz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接