非同期HttpWebResponse読み取り中に未処理のSocketExceptionをキャッチ
-
06-07-2019 - |
質問
HttpWebRequest.BeginGetResponse / EndGetResponseおよびHttpWebResponse.GetResponseStream()。BeginRead / EndReadへのすべての非同期呼び出しはtry / catchブロックから作成されますが、これらの例外は伝播し、それらを処理し、アプリケーションの終了を停止しません:
未処理の例外:System.IO.IOException:トランスポート接続からデータを読み取れません:確立された接続は、ホストマシンのソフトウェアによって中止されました。 ---> System.Net.Sockets.SocketException:確立された接続は、ホストマシンのソフトウェアによって中止されました
未処理の例外:System.IO.IOException:トランスポート接続からデータを読み取れません:既存の接続がリモートホストによって強制的に閉じられました。 ---> System.Net.Sockets.SocketException:リモートホストによって既存の接続が強制的に閉じられました
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
解決 2
2009年11月16日午前11時14分にMicrosoftが投稿
この問題は、.NET 4.0 Frameworkで解決されました。
ありがとうございます
ネットワーククラスライブラリチーム
https://connect.microsoft.com/VisualStudio/feedback /ViewFeedback.aspx?FeedbackID=510564
他のヒント
理由は、BegainGetResponseを開始したスレッドとは異なるスレッドで例外が発生したためだと思います。これは、呼び出しスタックの System.Threading.ExecutionContext.Run
呼び出しを説明しています。
例外が発生する前にtry catchブロックを終了する場合があり、ハンドラーなしで発生します。コードの一部を投稿してください。改善方法を確認できます