views:

143

answers:

2

I am having a weird issue happening with outputcache. I have multiple user controls on a page, one of which is a login control. The page and the login control is NOT cached, but other user controls are cached with VaryByParam. Now all of this works along with caching when I click on to different pages. But as soon as I login, other user controls on that page display old cached versions. If I refresh the page, I get the correct cached version of all user controls. The problem is only when a postback happens. For some reason on a postback, the cached version returned does not take into account the VaryByParam string. When searching for this online, I did see a similar problem being asked on asp.net, which had a code explaining this.

Why would postback cause the cache to return back invalid version ?

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"&gt;
<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" %>

Run the demo and you will see clicking between pages gets the correct cached version. But play around with clicking a page and causing a postback and then you will see that you get the wrong cache version sometimes.

A: 

I think this is a bug in ASP .Net, and until its solved, here is a workaround.

For every postback I want a fresh version and not a cached version. But otherwise I want the cached version. So I can look if what kind of request this is. If this is a 'POST' I will get a new version, if this is a 'GET' I will get the version from cache. To do this, I setup a VaryByCustom cache setting on the usercontrol. And in my global.asax did this:

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);
}
Garfield
A: 

From someone inside MS:

The output cache behavior for controls was originally written (and still is written) to key off of either the query-string collection or the form value collection. The internal logic determines which collection to look at based on whether the request is a GET or a POST. I agree that the behavior is less than obvious, but that was apparently the original intent of the control output caching behavior.

The two workarounds to include query string values are part of output cache decisions are:

  1. Mirror query-string values into hidden form variables if that is possible.
  2. Alternatively use the workaround you already discovered – which is to use VaryByCustom and GetVaryByCustomString. A custom implementation of GetVaryByCustomString can return a string containing one or more values read from Request.Querystring for POST requests to get the desired effect.
Garfield