How to determine if current request is an asynchronous postback, in ASP.NET Application_Error event

4.6k views Asked by At

Is it possible to determine whether the current request is an asynchronous postback (partial page update) from within the Application_Error event?

What's the best way to handle application errors when asynchronous postbacks are used?

In Application_Error, we are redirecting to different error pages but that doesn't work properly when the error is thrown during an asynchronous postback. We noticed that this holds true even when AllowCustomErrorsRedirect = false and we have an OnAsyncPostBackError handler to set the AsyncPostBackErrorMessage. During asynchronous postbacks, our AsyncPostBackErrorMessage is overwritten and the client receives a generic web page error instead.

3

There are 3 answers

3
Michiel van Oosterhout On BEST ANSWER

In the Application_Error method you no longer have direct access to the <asp:ScriptManager> control on the page. So it's too late to handle its AsyncPostBackError event.

If you want to prevent a redirect, you should check the request to see if it is in fact an asynchronous request. The <asp:UpdatePanel> causes a post back with the following HTTP header:

X-MicrosoftAjax:Delta=true

(also see: ScriptManager Enables AJAX In Your Web Apps)

A check for this header would look something like this:

HttpRequest request = HttpContext.Current.Request;
string header = request.Headers["X-MicrosoftAjax"];
if(header != null && header == "Delta=true") 
{
  // This is an async postback
}
else
{
  // Regular request
}

As to what would be an appropriate way to handle the exception is a different question imho.

0
BrianFinkel On

Within Application_Error, you actually can access ScriptManager to determine whether the current request is an asynchronous postback. The global object HttpContext.Current.Handler actually points to the page being serviced, which contains the ScriptManager object, which will tell you if the current request is asynchronous.

The following statement concisely illustrates how to access the ScriptManager object and get this information:

ScriptManager.GetCurrent(CType(HttpContext.Current.Handler, Page)).IsInAsyncPostBack

Of course, that statement will fail if the current request is not for a page, or if there is no ScriptManager on the current page, so here is a more robust pair of functions you can use inside Global.asax to make the determination:

Private Function GetCurrentScriptManager() As ScriptManager
    'Attempts to get the script manager for the current page, if there is one

    'Return nothing if the current request is not for a page
    If Not TypeOf HttpContext.Current.Handler Is Page Then Return Nothing

    'Get page
    Dim p As Page = CType(HttpContext.Current.Handler, Page)

    'Get ScriptManager (if there is one)
    Dim sm As ScriptManager = ScriptManager.GetCurrent(p)

    'Return the script manager (or nothing)
    Return sm
End Function

Private Function IsInAsyncPostback() As Boolean
    'Returns true if we are currently in an async postback to a page

    'Get current ScriptManager, if there is one
    Dim sm As ScriptManager = GetCurrentScriptManager()

    'Return false if no ScriptManager
    If sm Is Nothing Then Return False

    'Otherwise, use value from ScriptManager
    Return sm.IsInAsyncPostBack
End Function

Just call IsInAsyncPostback() from within Application_Error to get a boolean indicating the current state.

You're getting generic ASP.NET errors at the client because attempting to transfer / redirect an async request will generate more errors, replacing and thereby obfuscating the original error. You can use the code above to prevent transferring or redirecting in such cases.

Also note another discovery I made: Even though you can access the ScriptManager object using this method, for some reason setting its AsyncPostBackErrorMessage property from within Application_Error does not work. The new value is not passed to the client. Therefore, you will still need to handle the ScriptManager's OnAsyncPostBackError event in the page class.

0
jcj80 On

I had a similar scenario. What worked for me was calling Server.ClearError() in my event handler for the ScriptManager's AsyncPostBackError. This prevents the Global.asax Application_Error function from being called.