Getting the Sys.WebForms.PageRequestManagerParserErrorException while making an AJAX callback

Recently I encountered an issue wherein our customer was running into a client side AJAX exception, Sys.WebForms.PageRequestManagerParserErrorException, while trying to make an Async Postback from an ASPX page. This exception was happening for all the clients in a specific network and looked like this:

---------------------------
Microsoft Internet Explorer
---------------------------
Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, HttpModules, or server trace is enabled.

Details: Error parsing near  <SOME PLACE>
---------------------------
OK 
---------------------------

This issue generally comes up when the client is making an Async Postback and the response which comes back is not as expected. If anything gets appended to the response other than the expected HTML, or if the client gets a completely different response than what it expected, the client is not able to parse the response correctly and ends up throwing the above exception. The location of the response/request modification could be anywhere between the client and the server, including intermediary network devices. This article explains it really well.

Though the exception is pretty self explanatory it can be hard to track down who is modifying the response and/or even the request itself. In such cases one may have to rely on network traffic capturing tools like Netmon and Fiddler to troubleshoot it. So for investigating this issue we captured netmon and fiddler traces from the client and the server for both working and non-working scenarios. Though this clearly looked like a network issue as it was coming only for clients in specific network, we still wanted to know what was getting changed. Here is how the fiddler request and the response looks like for the test page in working scenario -

Request -

POST /AJAXWebSite/Test.aspx HTTP/1.1
Accept: */*
Accept-Language: en-us
Referer: https://mymachine/AJAXWebSite/Test.aspx
x-microsoftajax: Delta=true
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Cache-Control: no-cache
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; InfoPath.2; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MS-RTC EA 2)
Host: mymachine
Content-Length: 246
Connection: Keep-Alive
Pragma: no-cache

ScriptManager1=ScriptManager1%7CTimer1&__EVENTTARGET=Timer1&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwUJNjIzMzE1NzA5ZGT3MKmu9xSktVp3SfAtEYDZUmMU3Q%3D%3D&__EVENTVALIDATION=%2FwEWAgLSiq3NAwLs0bLrBj7PuCpvPWwAmr3CkDtU%2B87Qq6o8&TextBox1=&

Expected Response -

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 566
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/6.0
MicrosoftOfficeWebServer: 5.0_Pub
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Date: Tue, 21 Jul 2009 14:09:27 GMT

113|updatePanel|UpdatePanel1|
                <input name="TextBox1" type="text" value="7/21/2009 10:09:27 AM" id="TextBox1" />
            |0|hiddenField|__EVENTTARGET||0|hiddenField|__EVENTARGUMENT||52|hiddenField|__VIEWSTATE|/wEPDwUJNjIzMzE1NzA5ZGT3MKmu9xSktVp3SfAtEYDZUmMU3Q==|48|hiddenField|__EVENTVALIDATION|/wEWAgLSiq3NAwLs0bLrBj7PuCpvPWwAmr3CkDtU+87Qq6o8|6|asyncPostBackControlIDs||Timer1|0|postBackControlIDs|||13|updatePanelIDs||tUpdatePanel1|0|childUpdatePanelIDs|||12|panelsToRefreshIDs||UpdatePanel1|2|asyncPostBackTimeout||90|9|formAction||Test.aspx|

But when we took similar traces for the failing scenario here is what we saw for the same request -

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 2718
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/6.0
MicrosoftOfficeWebServer: 5.0_Pub
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Date: Tue, 21 Jul 2009 14:16:53 GMT

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="https://www.w3.org/1999/xhtml">
<head><title>

</title></head>
<body>
    <form name="form1" method="post" action="Test.aspx" id="form1">
<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNjIzMzE1NzA5ZGT3MKmu9xSktVp3SfAtEYDZUmMU3Q==" />
</div>

<script type="text/javascript">
//<![CDATA[
var theForm = document.forms['form1'];
if (!theForm) {
    theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}
//]]>
</script>

<script src="/aspnet_client/system_web/2_0_50727/WebForms.js" type="text/javascript"></script>

<script src="/AJAXWebSite/ScriptResource.axd?d=ktG6RH-5YekKOFKmPczdQtpmuIwrQ0_IN1WVRbcxrxJarwiTwmePaK1rX5K7SKYF6RcFAExALSoSedjYxsT-46bYYF7ifZVAG_-JOynQe0A1&amp;t=ffffffffa46422ae" type="text/javascript"></script>
<script src="/AJAXWebSite/ScriptResource.axd?d=ktG6RH-5YekKOFKmPczdQtpmuIwrQ0_IN1WVRbcxrxJarwiTwmePaK1rX5K7SKYFksyhgYfs5XBNWIel6UBRrkKMZWUoedc8dmuiqHrMtPg1&amp;t=ffffffffa46422ae" type="text/javascript"></script>
<script src="/AJAXWebSite/ScriptResource.axd?d=ktG6RH-5YekKOFKmPczdQtpmuIwrQ0_IN1WVRbcxrxJarwiTwmePaK1rX5K7SKYFQnR-aK0Xy6ZPnKAS2x4xTc249FkSXpb_JOTlKStYU3c1&amp;t=ffffffffa46422ae" type="text/javascript"></script>
<div>

    <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWAgLSiq3NAwLs0bLrBj7PuCpvPWwAmr3CkDtU+87Qq6o8" />
</div>
    <div>
        <script type="text/javascript">
//<![CDATA[
Sys.WebForms.PageRequestManager._initialize('ScriptManager1', document.getElementById('form1'));
Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tUpdatePanel1'], ['Timer1'], [], 90);
//]]>
</script>

        <span id="Timer1" style="visibility:hidden;display:none;"></span>
        <div id="UpdatePanel1">
                <input name="TextBox1" type="text" value="7/21/2009 10:16:53 AM" id="TextBox1" />
</div>
    </div>

<script type="text/javascript">
//<![CDATA[
Sys.Application.initialize();
Sys.Application.add_init(function() {
    $create(Sys.UI._Timer, {"enabled":true,"interval":10000,"uniqueID":"Timer1"}, null, null, $get("Timer1"));
});
//]]>
</script>
</form>
</body>
</html>

Instead of getting a response for the Async Postback we were getting a response for the entire page. So it was not possible for the client to parse through it and attach the content to the controls in the UpdatePanel1 and hence it was throwing the  Sys.WebForms.PageRequestManagerParserErrorException exception for the HTML tags etc. Now this led us to understand that the server was not treating the request as an Asynch Postback; rather it was treating it as a full postback and sending the entire HTML response back to the client.

In ASP.NET 3.5 and earlier we recognize the AJAX callback by the HTTP header “x-microsoftajax: Delta=true”. When we took a netmon trace between the client and the server we found the client was sending the above header as part of the HTTP request headers but it was never reaching the server. We then found that the customer had a non-Microsoft firewall which was removing all unrecognized HTTP headers including x-microsoftajax. This resulted in the server treating the request as a normal postback and the server responded back with the complete HTML instead of the partial response, causing the above exception on the client side.

There are few firewalls which are capable of removing the HTTP Headers. There are some which do not recognize the x-microsoftajax header as well. We can use one of the options below to fix the issue:

1. Turn off the option in the Firewall settings which disallows unrecognized HTTP Headers – the HTTP protocol gives the capability to write custom header(s) to developers. By disallowing unrecognized HTTP Headers the firewall is limiting this capability of the HTTP protocol.

2. Upgrade to Service Pack 1 of .NET Framework 3.5 – As there are few firewalls which disallow the x-microsoftajax header, we did a fix for UpdatePanel to send a form value in addition to the header to work around the broken proxies/firewalls issue in 3.5 SP1. Now AJAX callback requests send a form field “__ASYNCPOST=true” along with the request and  x-microsoftajax header. On the server side we check both the Form Field and the header to verify the AJAX request.

I hope this helps!