【问题标题】:OutputCache returns invalid version with PostBackOutputCache 使用 PostBack 返回无效版本
【发布时间】:2011-01-15 20:35:36
【问题描述】:

我遇到了一个关于输出缓存的奇怪问题。我在一个页面上有多个用户控件,其中一个是登录控件。页面和登录控件未缓存,但其他用户控件使用 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" %>

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

【问题讨论】:

    标签: asp.net postback outputcache


    【解决方案1】:

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

    对于每个回发,我想要一个新版本而不是缓存版本。但否则我想要缓存的版本。所以我可以看看这是一个什么样的请求。如果这是“POST”,我将获得一个新版本,如果这是“GET”,我将从缓存中获取版本。为此,我在用户控件上设置了 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);
    }
    

    【讨论】:

    • 如果正确实施,这肯定会返回一个新版本的页面,但似乎有一个缺点,就是缓存中出现了不再使用的页面版本。人们可以接受这个缺点并使用短期缓存持续时间作为折衷方案,但这仍然不是最好的。
    【解决方案2】:

    来自 MS 内部的某个人:

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

    在输出缓存决策中包含查询字符串值的两种解决方法是:

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

    【讨论】:

      【解决方案3】:

      我同意 Garfield 的观点,并且认为使用 VaryByCustom 的建议也是一个聪明的主意。为此,您可以简单地在 Global.asax 中使用 Response.Cache.SetNoServerCaching(),它只需要在 Global.asax 中检测页面是否为回发。 Here 是一个代码示例。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多