Cattura SocketException non gestita durante la lettura asincrona di HttpWebResponse
-
06-07-2019 - |
Domanda
Tutte le chiamate asincrone a HttpWebRequest.BeginGetResponse / EndGetResponse e HttpWebResponse.GetResponseStream (). BeginRead / EndRead sono fatte da blocchi try / catch, tuttavia, queste eccezioni si propagano e non lasciano una possibilità gestirle e arrestare la chiusura dell'applicazione:
Eccezione non gestita: System.IO.IOException: impossibile leggere i dati dalla connessione di trasporto: Una connessione stabilita è stata interrotta dal software nel computer host. --- > System.Net.Sockets.SocketException: una connessione stabilita è stata interrotta dal software nel computer host
Eccezione non gestita: System.IO.IOException: impossibile leggere i dati dalla connessione di trasporto: Una connessione esistente è stata forzatamente chiusa dall'host remoto. --- > System.Net.Sockets.SocketException: una connessione esistente è stata forzatamente chiusa dall'host remoto
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)
Frammenti di codice effettivi:
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: una segnalazione di bug è stata depositata su Microsoft Connect https: / /connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=510564
Soluzione 2
Inserito da Microsoft il 16/11/2009 alle 11:14
Questo problema è stato risolto in .NET 4.0 Framework.
Grazie
Team della libreria di classi di rete
https://connect.microsoft.com/VisualStudio/feedback /ViewFeedback.aspx?FeedbackID=510564
Altri suggerimenti
Penso che il motivo sia che l'eccezione è stata sollevata su un thread diverso da quello che ha avviato BegainGetResponse, e questo spiega la chiamata System.Threading.ExecutionContext.Run
nello stack di chiamate.
Il caso potrebbe essere che esci dal blocco try catch prima che venga sollevata l'eccezione, quindi si solleva senza alcun gestore, puoi per favore pubblicare la tua parte del codice in modo che io possa vedere come possiamo migliorarlo