Thursday, May 9, 2013

Sys.Webforms.PageRequestManagerServerErrorException actual cause


Copyright from: Rama Krishna and Ted Jardine
I finally figured out what is causing the Sys.WebForms.PageRequestManagerServerErrorException. Here are the details of my research:
It's probably a bug in the RoleManagerModule . The issue is that the RoleManagerModule, (which comes into picture when the role manager is enabled in the config) tries to add its cookie to Response's cookie collection. This is done in the EndRequest event of the Application. It should actually do it in the PreSendRequestHeaders event because the PreSendRequestHeaders is the last opportunity to modify the response headers. Under normal circumstances the  PreSendRequestHeaders  gets fired after the EndRequest event, but when Response.Flush is called the sequence may be reversed.
Now, the changes made in AJAX RTM which causes this issue are in PageRequestManager.RenderFormCallback function. When EventValidation is enabled in the page, the function calls Response.Flush (which causes the header to be sent). In this case the Application's EndRequest event is fired after the headers have been sent so an exception occurs in RoleManagerModule when it tries to send the response headers. This eventually leads to the page manager parser exception on the client side because the error response is appended to the actual response sent by the partial update.
There are some possible workarounds:
1. Disable caching of cookies in the RoleManager. For custom modules append cookies in the PreSendRequestHeaders event and not EndRequest event.
2. Handle the Application's Error event to clear the error from the Context selectively.
void Application_Error(object sender, EventArgs e)
{
  //There should be some checking done so that not all the errors
  //are cleared
  Context.ClearError();
}
 3. Disable EventValidation in the web form.
<%@ Page Language="C#" EnableEventValidation="false" %>
  <%@ Page Language="C#" EnableEventValidation="false" %> 
The issue can be repro'ed easily by setting a cookie in the EndRequest event:
void Application_EndRequest(object sender, EventArgs e)
{
  Response.Cookies.Add(new HttpCookie("Test""Test"));
}
And the following simple page will cause the issue:

<%@ Page Language="C#" EnableEventValidation="true" %>

<!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">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
         </div>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Button ID="Button1" runat="server"  Text="Button" />
                <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>
</body>
</html>
4. Writing a new rolemanager that works without any problems
5. Page ValidateRequest="false".
6. Check your firewall settings too. Reference:
7. Page_Load:
Session["FixAJAXSysBug"] = true;

UPDATE: If the problem pages aren't even using session, just turn session off for the page:
<%@ Page EnableSessionState="false" ... %>
Or better yet, set it in your base class to always be off, and turn it on for the pages where you need it on.
8. turn off the keep-alive of our SSL Connection. Reference "How to configure SSL correctly:
http://www.msexchange.org/articles-tutorials/exchange-server-2003/security-message-hygiene/SSL_Enabling_OWA_2003.html