views:

1168

answers:

3

All the asynchronous calls to HttpWebRequest.BeginGetResponse/EndGetResponse and HttpWebResponse.GetResponseStream().BeginRead/EndRead are made from try/catch blocks, however, these exceptions propagate and do not leave a chance handle them and stop application termination:

Unhandled Exception: System.IO.IOException: Unable to read data from the transport connection: An established connection was aborted by the software in your host machine. ---> System.Net.Sockets.SocketException: An established connection was aborted by the software in your host machine

Unhandled Exception: System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host

Unhandled Exception: System.IO.IOException: Unable to read data from the transport connection: An established connection was aborted by the software in your host machine. ---> System.Net.Sockets.SocketException: An established connection was aborted by the software in your host machine
   at System.Net.Sockets.Socket.BeginReceive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, AsyncCallback callback, Object state)
   at System.Net.Sockets.NetworkStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   --- End of inner exception stack trace ---
   at System.Net.Sockets.NetworkStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   at System.Net.PooledStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   at System.Net.ConnectStream.BeginReadWithoutValidation(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   at System.Net.ConnectStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   at System.IO.Compression.DeflateStream.ReadCallback(IAsyncResult baseStreamResult)
   at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
   at System.Net.ContextAwareResult.CompleteCallback(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Net.ContextAwareResult.Complete(IntPtr userToken)
   at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
   at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

Actual code fragments:

public static RequestState StartDownload(string url, string referer, RequestData data, DownloadEventHandler completedHandler, DownloadExceptionHandler failedHandler)
{
    RequestState state = null;

    try
    {
        var request = CreateWebRequest(url, referer, data);
        state = new RequestState(url, data, request)
        {
            DownloadCompleted = completedHandler;
            DownloadFailed = failedHandler;
        }

        state.ResponseAsyncResult = request.BeginGetResponse(WebResponseCallback, state);
        state.AsyncTimeoutHandle = ThreadPool.RegisterWaitForSingleObject(state.CompletedHandle, DownloadTimeoutCallback, state, TimeSpan.FromSeconds(data.DownloadTimeout), true);
    }
    catch(Exception ex)
    {
        Trace.TraceError(ex.ToString());
    }

    return state;
}

private static void DownloadTimeoutCallback(object state, bool timedOut)
{
    var requestState = (RequestState)state;

    try
    {
        requestState.AsyncTimeoutHandle.Unregister(null);

        if(timedOut)
        {
            requestState.Request.Abort();
        }
    }
    catch(Exception ex)
    {
        Trace.TraceError(ex.ToString());
    }
}

private static void WebResponseCallback(IAsyncResult asyncResult)
{
    var state = (RequestState)asyncResult.AsyncState;
    try
    {
        var response = (HttpWebResponse)state.Request.EndGetResponse(asyncResult);
        WebResponse(state, response);
    }
    catch (Exception ex)
    {
        Trace.TraceError(ex.ToString());
    }
}

private static void WebResponse(RequestState state, HttpWebResponse response)
{
    state.ActualUrl = state.Request.Address.ToString();
    state.Response = response;

    BeginRead(state);
}

private static void BeginRead(RequestState state)
{
    var stream = state.Response.GetResponseStream();
    state.ReadAsyncResult = stream.BeginRead(state.Buffer, 0, state.BufferSize, ReadCallBack, state);
}

private static void ReadCallBack(IAsyncResult asyncResult)
{
    var state = (RequestState)asyncResult.AsyncState;

    try
    {
        var stream = state.Response.GetResponseStream();
        var bytesRead = stream.EndRead(asyncResult);

        if (bytesRead > 0)
        {
            //there is still more data to read
            state.AppendResponseData(state.Buffer, 0, bytesRead);
            BeginRead(state);
        }
        else
        {
            state.Response.Close();
            state.InvokeDownloadCompleted();
        }       
    }
    catch(Exception ex)
    {
        Trace.TraceError(ex.ToString());
    }
}

PS: A bug report was filed at Microsoft Connect https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=510564

A: 

I think the reason is that the exception raised on a different thread than the one that initiated the BegainGetResponse, and this explains the System.Threading.ExecutionContext.Run call in the call stack. The case might be that you exit the try catch block before the exception gets raised, so it raises with no handler to it, can you please post your part of the code so I can see how we can improve it

bashmohandes
I have added the code fragments to the original question
AlexMinza
I think there is a missing part where you perform the BeginGetResponse
bashmohandes
I thought those were not very relevant to the example, but have included some more code anyway - hope this explains better the problem. Thanks!
AlexMinza
+1  A: 

This exception is happening on a completion port thread, and therefore there is no chance to catch it, as you dont own the thread on which it is occuring.

What we need to do is to get to the root cause. Can you get a network tracelog as per instructions in http://ferozedaud.blogspot.com/2009/08/tracing-with-systemnet.html and also get a network sniff using Wireshark? That should help us get to the root cause of why the client is aborting the connection.

feroze
I have found a relate discussion: http://windows-tech.info/13/60a2fc8702960be3.phpFrom what I see reflecting Socket.BeginReceive, the code checks for the state of the socket and if it is different from Success or IOPending - it throws an exception, which ultimately unloads the process as it cannot be caught by user code.
AlexMinza
Alex, we still need to see the tracelog, as per instructions I gave you. On the face of it, it looks like a bug in the .net framework, but to confirm, we need to see a tracelog.Is your app calling abort() on the request, by any chance?
feroze
Daud, thanks for submitting this issue to Microsoft Connect, hopefully this will attract the attention and it will be fixed soon. I have enabled System.Net tracing as per your instructions but this produces fairly large logs and slows down the system, which makes it harder to actually hit the error condition. The error appears once every few hours (after several thousands of successful HTTP requests). Currently, as a workaround, we use synchronous HttpWebRequest methods on Thread Pool threads to "simulate" asynchronous methods
AlexMinza
Posted by Microsoft on 11/16/2009 at 11:14 AMThis issue has been resolved in the .NET 4.0 Framework.Thank you,Network Class Library Teamhttps://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=510564
AlexMinza
A: 

Posted by Microsoft on 11/16/2009 at 11:14 AM

This issue has been resolved in the .NET 4.0 Framework.

Thank you,

Network Class Library Team

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=510564

AlexMinza