6

外部サービスからデータを取得する Web アプリがあります。リクエスト自体は、以下のコードのように行われます - 私が見る限り、非常に簡単です。リクエストを作成し、それを非同期的に起動して、コールバックにレスポンスを処理させます。私の開発環境では問題なく動作します。

public static void MakeRequest(Uri uri, Action<Stream> responseCallback)
        {
            WebRequest request = WebRequest.Create(uri);
            request.Proxy = null;
            request.Timeout = 8000;
            try
            {
                Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null)
                    .ContinueWith(task =>
                                      {
                                          WebResponse response = task.Result;
                                          Stream responseStream = response.GetResponseStream();
                                          responseCallback(response.GetResponseStream());
                                          responseStream.Close();
                                          response.Close();
                                      });
            } catch (Exception ex)
            {
                _log.Error("MakeRequest to " + uri + " went wrong.", ex);
            }
        }

ただし、外部のテスト環境と本番環境は、私には理解できない理由で、ターゲット URL に到達しない可能性があります。大丈夫、私は思った-リクエストのタイムアウトは、実際には誰にも害を及ぼすことはありません. ただし、この要求がタイムアウトするたびに ASP.NET がクラッシュし、IIS が再起動されたようです。イベント ログには、特に次のスタック トレースが表示されます。

StackTrace:    at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.get_Result()
   at MyApp.AsyncWebClient.<>c__DisplayClass2.<MakeRequest>b__0(Task`1 task)
   at System.Threading.Tasks.Task`1.<>c__DisplayClass17.<ContinueWith>b__16(Object obj)
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()

InnerException: System.Net.WebException

Message: Unable to connect to the remote server

StackTrace:    at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endMethod, TaskCompletionSource`1 tcs)

InnerException: System.Net.Sockets.SocketException

Message: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond

StackTrace:    at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
   at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Int32 timeout, Exception& exception)

..だから、それはすべて SocketException に要約されます、それは私には思えます。そしてその直後(同じ秒以内)に別のイベント(関連していると推測しています)が記録されます:

Exception Info: System.AggregateException
Stack:
   at System.Threading.Tasks.TaskExceptionHolder.Finalize()

私は非同期コードとスレッドのマスターではないので、これは私を超えていますが、Web 要求からのタイムアウトにより IIS がクラッシュするのは非常に奇妙に思えます。MakeRequestリクエストを同期的に実行するように再実装 しましたが、うまくいきました。これらの環境でもリクエストはタイムアウトしますが、損害は発生せず、その後もアプリは問題なく動作し続けます。

それで、私は問題を解決しましたが、なぜこれが起こるのですか?誰でも私を啓発できますか?:-)

4

1 に答える 1

12

継続は.Result、例外を反映している可能性があるという事実を処理する必要があります。そうしないと、未処理の例外が発生します。未処理の例外はプロセスを強制終了します。

.ContinueWith(task =>
{
    try {
        WebResponse response = task.Result;
        Stream responseStream = response.GetResponseStream();
        responseCallback(responseStream);
        responseStream.Close();
        response.Close();
    } catch(Exception ex) {
        // TODO: log ex, etc
    }
});

古い例外ハンドラーは、コールバックではなく、タスクの作成のみをカバーします。

于 2012-05-30T14:26:03.440 に答える