Nov 19

Fix AJAX Error – PageRequestManagerParserErrorException: The message received from the server could not be parsed

===== Update: Clarified need for global.asax file and contents =====

A fantasy sports (fantasy basketball / fantasy football) website I do some work for had some Ajax related issues some time ago. I recently came across the problem somewhere else and figured it might make sense to write it up.

There were error messages that were not consistent. In testing a page there might not be any problems, but then when it goes to a production server the problem shows up. Or maybe it does not have a problem when being accessed from one location, but then another user does have a problem. If you have these sorts of symptoms I’m here to tell you it might not be Ajax’s problem. Instead, we may need to blame the firewall. Typically the ajax error will say something like :

“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 more here] …

Some firewalls do not recognize AJAX headers. This causes the firewall to alter the message (by removing the header) that our servers send to the browser viewing the page. When that happens, the user’s browser cannot make sense of the response and gives the error mentioned above. We actually had users who were able to convince their network admin to disable an option on their firewall (temporarily) that is typically called something like “REMOVE UNKNOWN HEADERS”. When the option was disabled, the site functioned normally for them.

Unfortunately, disabling the users firewall is not a viable solution. One recommendation might be to have the admin “tell” the firewall about the header so it will recognize it and quit removing it. Depending on the type of firewall (a product called Watchguard was the offender in our test case) there may be a way to make certain headers (the ajax header) known rather than disabling them all. There is nothing to “fix” for us as it is more a flaw with the firewall than anything else; if you are encountering this problem you will need to work with your network admin on the problem.

All of that being said, we found that it can also often be fixed by code on the website end! That is a much better option, yes? So here’s all you have to do.

<asp:contentplaceholder id=”ContentPlaceHolderCodeForAjaxStrippingFirewalls” runat=”server”>
<script language=’javascript’ type=”text/javascript”>
function beginRequest(sender, args)
{
   var r=args.get_request();
   if (r.get_headers()[“X-MicrosoftAjax”])
   {
      
b=r.get_body();
       
var a=“__MicrosoftAjax=” + encodeURIComponent(r.get_headers()[“X-MicrosoftAjax”]);
       if (b!=null  && b.length>0)
       {
             b+=
“&” ;
       }
       else b= “” ;
       r.set_body(b+a);
     }
}
</script>
</asp:contentplaceholder>

Note: I put this inside a contentplaceholder (I am using masterpages) so I didn’t have to include it manually on every page. If you are not utilizing masterpages then you could just put the script on each page that uses ajax. 

Now, we need something to call this. I put a call to it in my global.asax file within the method Application_BeginRequest:

void Application_BeginRequest(object sender, EventArgs e)
    {
        // first  event in the pipeline.
        // I’m going to use this to try to intercept ajax headers when they get all messed up by firewalls
        // I got the information about how to do this the below url:
        // http://forums.asp.net/p/1144748/1850717.aspx
        HttpRequest request = HttpContext.Current.Request;
        if (request.Headers[“X-MicrosoftAjax”] == null && request.Form[“__MicrosoftAjax”] != null)
        {
         ArrayList list = new ArrayList();
         list.Add(request.Form[“__MicrosoftAjax”]);
         Type t = request.Headers.GetType();
         //lock (request.Headers)
         //{
            t.InvokeMember(“MakeReadWrite”, System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, request.Headers, null);
            t.InvokeMember(“InvalidateCachedArrays”, System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, request.Headers, null);
            t.InvokeMember(“BaseSet”, System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, request.Headers, new object[] { “X-MicrosoftAjax”, list });
            t.InvokeMember(“MakeReadOnly”, System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, request.Headers, null);
         //}
        }
    }

 

Do those two things and and the problem goes bye bye, and the network admins get to keep their silly little rules in place.

Note2: I found the hint about what might be causing the problem here. I’m not entirely sure where I found the fix… it was a long day thank you… but it works.