Monday, November 15, 2004

330.aspx

Asynchronous vs synchronous msxml 4 http call

One site I work on has been ported from ASP to ASP.NET. Many clients have a bookmark to the old ASP page which does not exist anymore. Redirection is possible but it is slow over mobile networks like GSM/GPRS/UTMS. To work around the problem I have implemented an ASP page that does a http GET request to the correct ASP.NET page on the localhost and sends the result back to the user.


This is the core:


    Public Sub getURL(ByVal sURL)
        '**
        'Purpose: Request the url and send the output to the end user
        Dim oRequest
        Dim sUserAgent
        Dim sAccept
        oRequest = Server.CreateObject("MSXML2.ServerXMLHTTP.4.0")
 
        'prepare the request
        On Error Resume Next
        oRequest.open("GET", sURL, True)
 
        sUserAgent = Request.ServerVariables("HTTP_USER_AGENT")
        sAccept = Request.ServerVariables("HTTP_ACCEPT")
        If sUserAgent <> "" Then oRequest.setRequestHeader("User-Agent", sUserAgent)
        If sAccept <> "" Then oRequest.setRequestHeader("Accept", sAccept)
 
        'send and wait for reply
        oRequest.send()
        oRequest.waitForResponse(HTTP_REQUEST_TIMEOUT)
 
        'Check if ther is an error
        lRequestError = err.number
        On Error GoTo 0
        If lRequestError <> 0 Then handleError(ERROR_REQUEST_FAILED)
        If oRequest.readyState <> 4 Then  '4 => request complete
            oRequest.abort()
            handleError(ERROR_REQUEST_TIMEOUT) 'Does Response.End()
        End If
 
        'Send the response back to the user
        Response.ContentType = oRequest.getResponseHeader("Content-Type")
        Response.Expires = oRequest.getResponseHeader("Expires")
        Response.Write(oRequest.responseText)
        oRequest = Nothing
    End Sub

I have a strange problem in a Win2k3 environment with a lot of machines in NLB. When page1.asp calls page1.aspx I see the following time taken fields in the IIS log:
Page1.asp: 50 ms
Page1.aspx: 29995 ms


These results are impossible as page1.asp executes page1.aspx and waits for page1.aspx to complete output before it sends it to the client. So the call time of Page1.aspx must be lower than the call tome of Page1.asp. It seems like the aspx page waits for the asp page to close the connection somehow. The interesting thing is that it does not have this problem if it calls a remote server.


We found the fix but I haven't managed to epxlain to myself why it works. I guess the asynchronous thread causes problems, but why the heck does it only cause problems when going to localhost?


The fix is to make the request synchronously by changing the code like this:


        'prepare the request
        On Error Resume Next
        oRequest.open("GET", sURL, True False)
 
        sUserAgent = Request.ServerVariables("HTTP_USER_AGENT")
        sAccept = Request.ServerVariables("HTTP_ACCEPT")
        If sUserAgent <> "" Then oRequest.setRequestHeader("User-Agent", sUserAgent)
        If sAccept <> "" Then oRequest.setRequestHeader("Accept", sAccept)
 
        'send and wait for reply
        oRequest.send()
        oRequest.waitForResponse(HTTP_REQUEST_TIMEOUT)
 
        'Check if ther is an error
        lRequestError = err.number
        On Error GoTo 0
        If lRequestError <> 0 Then handleError(ERROR_REQUEST_FAILED)
        If oRequest.readyState <> 4 Then  '4 => request complete
            oRequest.abort()
            handleError(ERROR_REQUEST_TIMEOUT) 'Does Response.End()
        End If

Explanations are more than welcome.

No comments:

Post a Comment