OutputCache返回PostBack的无效版本

时间:2010-02-11 19:00:38

标签: asp.net postback outputcache

我在使用outputcache时遇到了一个奇怪的问题。我在页面上有多个用户控件,其中一个是登录控件。页面和登录控件未缓存,但其他用户控件使用VaryByParam进行缓存。现在,当我点击不同的页面时,所有这些都与缓存一起工作。但是一旦我登录,该页面上的其他用户控件就会显示旧的缓存版本。如果我刷新页面,我会获得所有用户控件的正确缓存版本。问题出现在发生回发时。由于某些原因,在回发时,返回的缓存版本不考虑VaryByParam字符串。在网上搜索时,我确实在asp.net上看到了一个类似的问题,它有一个代码解释这个问题。

为什么回发会导致缓存返回无效版本?

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>
<%@ Register src="WebUserControl1.ascx" tagname="WebUserControl1" tagprefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>  
</head>
<body>
    <form id="form1" runat="server">       
        <uc1:WebUserControl1 ID="WebUserControl11" runat="server" EnableViewState="false" />           
    </form>
</body>
</html>

WebUserControl1.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="WebUserControl1.ascx.cs" Inherits="WebApplication1.WebUserControl1" %>
<%@ OutputCache Duration="3600" VaryByParam="MenuID" %>
<asp:LinkButton ID="test" runat="server" Text="PostBack"></asp:LinkButton>
<br /><br />
<a href="Default.aspx?menuid=1">1</a> - <a href="Default.aspx?menuid=2">2</a> - <a href="Default.aspx?menuid=3">3</a>
<br /><br />
MenuID: <%= Request.QueryString["MenuID"] != null ? Request.QueryString["MenuID"].ToString() : "null" %>

运行演示,您将看到页面之间的点击获得正确的缓存版本。但是,点击一个页面并导致回发,然后你会发现你有时会得到错误的缓存版本。

3 个答案:

答案 0 :(得分:2)

我认为这是ASP .Net中的一个错误,在解决之前,这是一个解决方法。

对于每个回发,我想要一个新版本,而不是一个缓存版本。但否则我想要缓存版本。所以我可以看看这是什么样的请求。如果这是'POST',我会得到一个新版本,如果这是'GET',我将从缓存中获取版本。为此,我在usercontrol上设置了VaryByCustom缓存设置。在我的global.asax中做到了这一点:

public override string GetVaryByCustomString(HttpContext context, string arg)
{
    if (arg.Trim().ToLower() == "getorpost")
    {
           //for a POST request (postback) force to return back a non cached output
            if (context.Request.RequestType.Equals("POST"))
            {
                return "post" + DateTime.Now.Ticks;
            }
            return "get";
     }
     return base.GetVaryByCustomString(context, arg);
}

答案 1 :(得分:0)

来自MS内部的人:

控件的输出缓存行为最初编写(并且仍然被编写)以关键字查询字符串集合或表单值集合。内部逻辑根据请求是GET还是POST来确定要查看的集合。我同意这种行为不太明显,但这显然是控制输出缓存行为的最初意图。

包含查询字符串值的两个变通方法是输出缓存决策的一部分:

  1. 将查询字符串值镜像到 隐藏的表单变量(如果是) 可能的。
  2. 或者使用解决方法 已经发现 - 这是用的 VaryByCustom和 GetVaryByCustomString。一个习俗 实施 GetVaryByCustomString可以返回一个 包含一个或多个值的字符串 从Request.Querystring中读取 POST请求获得所需 效果。

答案 2 :(得分:0)

我同意加菲尔德的原因,并认为使用VaryByCustom的建议也是一个明智的想法。为了做到这一点,你可以简单地在Global.asax中使用Response.Cache.SetNoServerCaching(),它只需要在Global.asax中检测页面是否是回发。 Here是一个代码示例。