Skip to main content
 首页 » 编程设计

c#之在异步 HttpWebResponse 读取期间捕获未处理的 SocketException

2024年01月13日29shihaiming

所有对 HttpWebRequest.BeginGetResponse/EndGetResponse 和 HttpWebResponse.GetResponseStream().BeginRead/EndRead 的异步调用都是从 try/catch block 进行的,但是,这些异常会传播并且不会留下处理它们和停止应用程序终止的机会:

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) 

实际代码片段:

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:在 Microsoft Connect https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=510564 上提交了错误报告

请您参考如下方法:

我认为原因是在与启动 BegainGetResponse 的线程不同的线程上引发了异常,这解释了调用堆栈中的 System.Threading.ExecutionContext.Run 调用。 情况可能是您在引发异常之前退出了 try catch block ,因此它在没有处理程序的情况下引发,能否请您发布您的代码部分,以便我看看我们如何改进它